162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <net/devlink.h> 562306a36Sopenharmony_ci#include "ice_sched.h" 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/** 862306a36Sopenharmony_ci * ice_sched_add_root_node - Insert the Tx scheduler root node in SW DB 962306a36Sopenharmony_ci * @pi: port information structure 1062306a36Sopenharmony_ci * @info: Scheduler element information from firmware 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * This function inserts the root node of the scheduling tree topology 1362306a36Sopenharmony_ci * to the SW DB. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_cistatic int 1662306a36Sopenharmony_ciice_sched_add_root_node(struct ice_port_info *pi, 1762306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data *info) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci struct ice_sched_node *root; 2062306a36Sopenharmony_ci struct ice_hw *hw; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci if (!pi) 2362306a36Sopenharmony_ci return -EINVAL; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci hw = pi->hw; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci root = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*root), GFP_KERNEL); 2862306a36Sopenharmony_ci if (!root) 2962306a36Sopenharmony_ci return -ENOMEM; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci /* coverity[suspicious_sizeof] */ 3262306a36Sopenharmony_ci root->children = devm_kcalloc(ice_hw_to_dev(hw), hw->max_children[0], 3362306a36Sopenharmony_ci sizeof(*root), GFP_KERNEL); 3462306a36Sopenharmony_ci if (!root->children) { 3562306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), root); 3662306a36Sopenharmony_ci return -ENOMEM; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci memcpy(&root->info, info, sizeof(*info)); 4062306a36Sopenharmony_ci pi->root = root; 4162306a36Sopenharmony_ci return 0; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/** 4562306a36Sopenharmony_ci * ice_sched_find_node_by_teid - Find the Tx scheduler node in SW DB 4662306a36Sopenharmony_ci * @start_node: pointer to the starting ice_sched_node struct in a sub-tree 4762306a36Sopenharmony_ci * @teid: node TEID to search 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * This function searches for a node matching the TEID in the scheduling tree 5062306a36Sopenharmony_ci * from the SW DB. The search is recursive and is restricted by the number of 5162306a36Sopenharmony_ci * layers it has searched through; stopping at the max supported layer. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * This function needs to be called when holding the port_info->sched_lock 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistruct ice_sched_node * 5662306a36Sopenharmony_ciice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci u16 i; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* The TEID is same as that of the start_node */ 6162306a36Sopenharmony_ci if (ICE_TXSCHED_GET_NODE_TEID(start_node) == teid) 6262306a36Sopenharmony_ci return start_node; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* The node has no children or is at the max layer */ 6562306a36Sopenharmony_ci if (!start_node->num_children || 6662306a36Sopenharmony_ci start_node->tx_sched_layer >= ICE_AQC_TOPO_MAX_LEVEL_NUM || 6762306a36Sopenharmony_ci start_node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) 6862306a36Sopenharmony_ci return NULL; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Check if TEID matches to any of the children nodes */ 7162306a36Sopenharmony_ci for (i = 0; i < start_node->num_children; i++) 7262306a36Sopenharmony_ci if (ICE_TXSCHED_GET_NODE_TEID(start_node->children[i]) == teid) 7362306a36Sopenharmony_ci return start_node->children[i]; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* Search within each child's sub-tree */ 7662306a36Sopenharmony_ci for (i = 0; i < start_node->num_children; i++) { 7762306a36Sopenharmony_ci struct ice_sched_node *tmp; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci tmp = ice_sched_find_node_by_teid(start_node->children[i], 8062306a36Sopenharmony_ci teid); 8162306a36Sopenharmony_ci if (tmp) 8262306a36Sopenharmony_ci return tmp; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return NULL; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/** 8962306a36Sopenharmony_ci * ice_aqc_send_sched_elem_cmd - send scheduling elements cmd 9062306a36Sopenharmony_ci * @hw: pointer to the HW struct 9162306a36Sopenharmony_ci * @cmd_opc: cmd opcode 9262306a36Sopenharmony_ci * @elems_req: number of elements to request 9362306a36Sopenharmony_ci * @buf: pointer to buffer 9462306a36Sopenharmony_ci * @buf_size: buffer size in bytes 9562306a36Sopenharmony_ci * @elems_resp: returns total number of elements response 9662306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * This function sends a scheduling elements cmd (cmd_opc) 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic int 10162306a36Sopenharmony_ciice_aqc_send_sched_elem_cmd(struct ice_hw *hw, enum ice_adminq_opc cmd_opc, 10262306a36Sopenharmony_ci u16 elems_req, void *buf, u16 buf_size, 10362306a36Sopenharmony_ci u16 *elems_resp, struct ice_sq_cd *cd) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct ice_aqc_sched_elem_cmd *cmd; 10662306a36Sopenharmony_ci struct ice_aq_desc desc; 10762306a36Sopenharmony_ci int status; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci cmd = &desc.params.sched_elem_cmd; 11062306a36Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, cmd_opc); 11162306a36Sopenharmony_ci cmd->num_elem_req = cpu_to_le16(elems_req); 11262306a36Sopenharmony_ci desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 11362306a36Sopenharmony_ci status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 11462306a36Sopenharmony_ci if (!status && elems_resp) 11562306a36Sopenharmony_ci *elems_resp = le16_to_cpu(cmd->num_elem_resp); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return status; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/** 12162306a36Sopenharmony_ci * ice_aq_query_sched_elems - query scheduler elements 12262306a36Sopenharmony_ci * @hw: pointer to the HW struct 12362306a36Sopenharmony_ci * @elems_req: number of elements to query 12462306a36Sopenharmony_ci * @buf: pointer to buffer 12562306a36Sopenharmony_ci * @buf_size: buffer size in bytes 12662306a36Sopenharmony_ci * @elems_ret: returns total number of elements returned 12762306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * Query scheduling elements (0x0404) 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ciint 13262306a36Sopenharmony_ciice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req, 13362306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data *buf, u16 buf_size, 13462306a36Sopenharmony_ci u16 *elems_ret, struct ice_sq_cd *cd) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_get_sched_elems, 13762306a36Sopenharmony_ci elems_req, (void *)buf, buf_size, 13862306a36Sopenharmony_ci elems_ret, cd); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/** 14262306a36Sopenharmony_ci * ice_sched_add_node - Insert the Tx scheduler node in SW DB 14362306a36Sopenharmony_ci * @pi: port information structure 14462306a36Sopenharmony_ci * @layer: Scheduler layer of the node 14562306a36Sopenharmony_ci * @info: Scheduler element information from firmware 14662306a36Sopenharmony_ci * @prealloc_node: preallocated ice_sched_node struct for SW DB 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * This function inserts a scheduler node to the SW DB. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ciint 15162306a36Sopenharmony_ciice_sched_add_node(struct ice_port_info *pi, u8 layer, 15262306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data *info, 15362306a36Sopenharmony_ci struct ice_sched_node *prealloc_node) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data elem; 15662306a36Sopenharmony_ci struct ice_sched_node *parent; 15762306a36Sopenharmony_ci struct ice_sched_node *node; 15862306a36Sopenharmony_ci struct ice_hw *hw; 15962306a36Sopenharmony_ci int status; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (!pi) 16262306a36Sopenharmony_ci return -EINVAL; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci hw = pi->hw; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* A valid parent node should be there */ 16762306a36Sopenharmony_ci parent = ice_sched_find_node_by_teid(pi->root, 16862306a36Sopenharmony_ci le32_to_cpu(info->parent_teid)); 16962306a36Sopenharmony_ci if (!parent) { 17062306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "Parent Node not found for parent_teid=0x%x\n", 17162306a36Sopenharmony_ci le32_to_cpu(info->parent_teid)); 17262306a36Sopenharmony_ci return -EINVAL; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* query the current node information from FW before adding it 17662306a36Sopenharmony_ci * to the SW DB 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci status = ice_sched_query_elem(hw, le32_to_cpu(info->node_teid), &elem); 17962306a36Sopenharmony_ci if (status) 18062306a36Sopenharmony_ci return status; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (prealloc_node) 18362306a36Sopenharmony_ci node = prealloc_node; 18462306a36Sopenharmony_ci else 18562306a36Sopenharmony_ci node = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*node), GFP_KERNEL); 18662306a36Sopenharmony_ci if (!node) 18762306a36Sopenharmony_ci return -ENOMEM; 18862306a36Sopenharmony_ci if (hw->max_children[layer]) { 18962306a36Sopenharmony_ci /* coverity[suspicious_sizeof] */ 19062306a36Sopenharmony_ci node->children = devm_kcalloc(ice_hw_to_dev(hw), 19162306a36Sopenharmony_ci hw->max_children[layer], 19262306a36Sopenharmony_ci sizeof(*node), GFP_KERNEL); 19362306a36Sopenharmony_ci if (!node->children) { 19462306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), node); 19562306a36Sopenharmony_ci return -ENOMEM; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci node->in_use = true; 20062306a36Sopenharmony_ci node->parent = parent; 20162306a36Sopenharmony_ci node->tx_sched_layer = layer; 20262306a36Sopenharmony_ci parent->children[parent->num_children++] = node; 20362306a36Sopenharmony_ci node->info = elem; 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/** 20862306a36Sopenharmony_ci * ice_aq_delete_sched_elems - delete scheduler elements 20962306a36Sopenharmony_ci * @hw: pointer to the HW struct 21062306a36Sopenharmony_ci * @grps_req: number of groups to delete 21162306a36Sopenharmony_ci * @buf: pointer to buffer 21262306a36Sopenharmony_ci * @buf_size: buffer size in bytes 21362306a36Sopenharmony_ci * @grps_del: returns total number of elements deleted 21462306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * Delete scheduling elements (0x040F) 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_cistatic int 21962306a36Sopenharmony_ciice_aq_delete_sched_elems(struct ice_hw *hw, u16 grps_req, 22062306a36Sopenharmony_ci struct ice_aqc_delete_elem *buf, u16 buf_size, 22162306a36Sopenharmony_ci u16 *grps_del, struct ice_sq_cd *cd) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_delete_sched_elems, 22462306a36Sopenharmony_ci grps_req, (void *)buf, buf_size, 22562306a36Sopenharmony_ci grps_del, cd); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/** 22962306a36Sopenharmony_ci * ice_sched_remove_elems - remove nodes from HW 23062306a36Sopenharmony_ci * @hw: pointer to the HW struct 23162306a36Sopenharmony_ci * @parent: pointer to the parent node 23262306a36Sopenharmony_ci * @num_nodes: number of nodes 23362306a36Sopenharmony_ci * @node_teids: array of node teids to be deleted 23462306a36Sopenharmony_ci * 23562306a36Sopenharmony_ci * This function remove nodes from HW 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_cistatic int 23862306a36Sopenharmony_ciice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent, 23962306a36Sopenharmony_ci u16 num_nodes, u32 *node_teids) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct ice_aqc_delete_elem *buf; 24262306a36Sopenharmony_ci u16 i, num_groups_removed = 0; 24362306a36Sopenharmony_ci u16 buf_size; 24462306a36Sopenharmony_ci int status; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci buf_size = struct_size(buf, teid, num_nodes); 24762306a36Sopenharmony_ci buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL); 24862306a36Sopenharmony_ci if (!buf) 24962306a36Sopenharmony_ci return -ENOMEM; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci buf->hdr.parent_teid = parent->info.node_teid; 25262306a36Sopenharmony_ci buf->hdr.num_elems = cpu_to_le16(num_nodes); 25362306a36Sopenharmony_ci for (i = 0; i < num_nodes; i++) 25462306a36Sopenharmony_ci buf->teid[i] = cpu_to_le32(node_teids[i]); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size, 25762306a36Sopenharmony_ci &num_groups_removed, NULL); 25862306a36Sopenharmony_ci if (status || num_groups_removed != 1) 25962306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "remove node failed FW error %d\n", 26062306a36Sopenharmony_ci hw->adminq.sq_last_status); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), buf); 26362306a36Sopenharmony_ci return status; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/** 26762306a36Sopenharmony_ci * ice_sched_get_first_node - get the first node of the given layer 26862306a36Sopenharmony_ci * @pi: port information structure 26962306a36Sopenharmony_ci * @parent: pointer the base node of the subtree 27062306a36Sopenharmony_ci * @layer: layer number 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * This function retrieves the first node of the given layer from the subtree 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_cistatic struct ice_sched_node * 27562306a36Sopenharmony_ciice_sched_get_first_node(struct ice_port_info *pi, 27662306a36Sopenharmony_ci struct ice_sched_node *parent, u8 layer) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci return pi->sib_head[parent->tc_num][layer]; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/** 28262306a36Sopenharmony_ci * ice_sched_get_tc_node - get pointer to TC node 28362306a36Sopenharmony_ci * @pi: port information structure 28462306a36Sopenharmony_ci * @tc: TC number 28562306a36Sopenharmony_ci * 28662306a36Sopenharmony_ci * This function returns the TC node pointer 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistruct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci u8 i; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (!pi || !pi->root) 29362306a36Sopenharmony_ci return NULL; 29462306a36Sopenharmony_ci for (i = 0; i < pi->root->num_children; i++) 29562306a36Sopenharmony_ci if (pi->root->children[i]->tc_num == tc) 29662306a36Sopenharmony_ci return pi->root->children[i]; 29762306a36Sopenharmony_ci return NULL; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/** 30162306a36Sopenharmony_ci * ice_free_sched_node - Free a Tx scheduler node from SW DB 30262306a36Sopenharmony_ci * @pi: port information structure 30362306a36Sopenharmony_ci * @node: pointer to the ice_sched_node struct 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * This function frees up a node from SW DB as well as from HW 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * This function needs to be called with the port_info->sched_lock held 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_civoid ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct ice_sched_node *parent; 31262306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 31362306a36Sopenharmony_ci u8 i, j; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Free the children before freeing up the parent node 31662306a36Sopenharmony_ci * The parent array is updated below and that shifts the nodes 31762306a36Sopenharmony_ci * in the array. So always pick the first child if num children > 0 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci while (node->num_children) 32062306a36Sopenharmony_ci ice_free_sched_node(pi, node->children[0]); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* Leaf, TC and root nodes can't be deleted by SW */ 32362306a36Sopenharmony_ci if (node->tx_sched_layer >= hw->sw_entry_point_layer && 32462306a36Sopenharmony_ci node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC && 32562306a36Sopenharmony_ci node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT && 32662306a36Sopenharmony_ci node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) { 32762306a36Sopenharmony_ci u32 teid = le32_to_cpu(node->info.node_teid); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ice_sched_remove_elems(hw, node->parent, 1, &teid); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci parent = node->parent; 33262306a36Sopenharmony_ci /* root has no parent */ 33362306a36Sopenharmony_ci if (parent) { 33462306a36Sopenharmony_ci struct ice_sched_node *p; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* update the parent */ 33762306a36Sopenharmony_ci for (i = 0; i < parent->num_children; i++) 33862306a36Sopenharmony_ci if (parent->children[i] == node) { 33962306a36Sopenharmony_ci for (j = i + 1; j < parent->num_children; j++) 34062306a36Sopenharmony_ci parent->children[j - 1] = 34162306a36Sopenharmony_ci parent->children[j]; 34262306a36Sopenharmony_ci parent->num_children--; 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci p = ice_sched_get_first_node(pi, node, node->tx_sched_layer); 34762306a36Sopenharmony_ci while (p) { 34862306a36Sopenharmony_ci if (p->sibling == node) { 34962306a36Sopenharmony_ci p->sibling = node->sibling; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci p = p->sibling; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* update the sibling head if head is getting removed */ 35662306a36Sopenharmony_ci if (pi->sib_head[node->tc_num][node->tx_sched_layer] == node) 35762306a36Sopenharmony_ci pi->sib_head[node->tc_num][node->tx_sched_layer] = 35862306a36Sopenharmony_ci node->sibling; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), node->children); 36262306a36Sopenharmony_ci kfree(node->name); 36362306a36Sopenharmony_ci xa_erase(&pi->sched_node_ids, node->id); 36462306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), node); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/** 36862306a36Sopenharmony_ci * ice_aq_get_dflt_topo - gets default scheduler topology 36962306a36Sopenharmony_ci * @hw: pointer to the HW struct 37062306a36Sopenharmony_ci * @lport: logical port number 37162306a36Sopenharmony_ci * @buf: pointer to buffer 37262306a36Sopenharmony_ci * @buf_size: buffer size in bytes 37362306a36Sopenharmony_ci * @num_branches: returns total number of queue to port branches 37462306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Get default scheduler topology (0x400) 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_cistatic int 37962306a36Sopenharmony_ciice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport, 38062306a36Sopenharmony_ci struct ice_aqc_get_topo_elem *buf, u16 buf_size, 38162306a36Sopenharmony_ci u8 *num_branches, struct ice_sq_cd *cd) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct ice_aqc_get_topo *cmd; 38462306a36Sopenharmony_ci struct ice_aq_desc desc; 38562306a36Sopenharmony_ci int status; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci cmd = &desc.params.get_topo; 38862306a36Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_dflt_topo); 38962306a36Sopenharmony_ci cmd->port_num = lport; 39062306a36Sopenharmony_ci status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 39162306a36Sopenharmony_ci if (!status && num_branches) 39262306a36Sopenharmony_ci *num_branches = cmd->num_branches; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return status; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci/** 39862306a36Sopenharmony_ci * ice_aq_add_sched_elems - adds scheduling element 39962306a36Sopenharmony_ci * @hw: pointer to the HW struct 40062306a36Sopenharmony_ci * @grps_req: the number of groups that are requested to be added 40162306a36Sopenharmony_ci * @buf: pointer to buffer 40262306a36Sopenharmony_ci * @buf_size: buffer size in bytes 40362306a36Sopenharmony_ci * @grps_added: returns total number of groups added 40462306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 40562306a36Sopenharmony_ci * 40662306a36Sopenharmony_ci * Add scheduling elements (0x0401) 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_cistatic int 40962306a36Sopenharmony_ciice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req, 41062306a36Sopenharmony_ci struct ice_aqc_add_elem *buf, u16 buf_size, 41162306a36Sopenharmony_ci u16 *grps_added, struct ice_sq_cd *cd) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_add_sched_elems, 41462306a36Sopenharmony_ci grps_req, (void *)buf, buf_size, 41562306a36Sopenharmony_ci grps_added, cd); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/** 41962306a36Sopenharmony_ci * ice_aq_cfg_sched_elems - configures scheduler elements 42062306a36Sopenharmony_ci * @hw: pointer to the HW struct 42162306a36Sopenharmony_ci * @elems_req: number of elements to configure 42262306a36Sopenharmony_ci * @buf: pointer to buffer 42362306a36Sopenharmony_ci * @buf_size: buffer size in bytes 42462306a36Sopenharmony_ci * @elems_cfgd: returns total number of elements configured 42562306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 42662306a36Sopenharmony_ci * 42762306a36Sopenharmony_ci * Configure scheduling elements (0x0403) 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_cistatic int 43062306a36Sopenharmony_ciice_aq_cfg_sched_elems(struct ice_hw *hw, u16 elems_req, 43162306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data *buf, u16 buf_size, 43262306a36Sopenharmony_ci u16 *elems_cfgd, struct ice_sq_cd *cd) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_cfg_sched_elems, 43562306a36Sopenharmony_ci elems_req, (void *)buf, buf_size, 43662306a36Sopenharmony_ci elems_cfgd, cd); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/** 44062306a36Sopenharmony_ci * ice_aq_move_sched_elems - move scheduler elements 44162306a36Sopenharmony_ci * @hw: pointer to the HW struct 44262306a36Sopenharmony_ci * @grps_req: number of groups to move 44362306a36Sopenharmony_ci * @buf: pointer to buffer 44462306a36Sopenharmony_ci * @buf_size: buffer size in bytes 44562306a36Sopenharmony_ci * @grps_movd: returns total number of groups moved 44662306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 44762306a36Sopenharmony_ci * 44862306a36Sopenharmony_ci * Move scheduling elements (0x0408) 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_ciint 45162306a36Sopenharmony_ciice_aq_move_sched_elems(struct ice_hw *hw, u16 grps_req, 45262306a36Sopenharmony_ci struct ice_aqc_move_elem *buf, u16 buf_size, 45362306a36Sopenharmony_ci u16 *grps_movd, struct ice_sq_cd *cd) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_move_sched_elems, 45662306a36Sopenharmony_ci grps_req, (void *)buf, buf_size, 45762306a36Sopenharmony_ci grps_movd, cd); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/** 46162306a36Sopenharmony_ci * ice_aq_suspend_sched_elems - suspend scheduler elements 46262306a36Sopenharmony_ci * @hw: pointer to the HW struct 46362306a36Sopenharmony_ci * @elems_req: number of elements to suspend 46462306a36Sopenharmony_ci * @buf: pointer to buffer 46562306a36Sopenharmony_ci * @buf_size: buffer size in bytes 46662306a36Sopenharmony_ci * @elems_ret: returns total number of elements suspended 46762306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * Suspend scheduling elements (0x0409) 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_cistatic int 47262306a36Sopenharmony_ciice_aq_suspend_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf, 47362306a36Sopenharmony_ci u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_suspend_sched_elems, 47662306a36Sopenharmony_ci elems_req, (void *)buf, buf_size, 47762306a36Sopenharmony_ci elems_ret, cd); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci/** 48162306a36Sopenharmony_ci * ice_aq_resume_sched_elems - resume scheduler elements 48262306a36Sopenharmony_ci * @hw: pointer to the HW struct 48362306a36Sopenharmony_ci * @elems_req: number of elements to resume 48462306a36Sopenharmony_ci * @buf: pointer to buffer 48562306a36Sopenharmony_ci * @buf_size: buffer size in bytes 48662306a36Sopenharmony_ci * @elems_ret: returns total number of elements resumed 48762306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 48862306a36Sopenharmony_ci * 48962306a36Sopenharmony_ci * resume scheduling elements (0x040A) 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_cistatic int 49262306a36Sopenharmony_ciice_aq_resume_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf, 49362306a36Sopenharmony_ci u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_resume_sched_elems, 49662306a36Sopenharmony_ci elems_req, (void *)buf, buf_size, 49762306a36Sopenharmony_ci elems_ret, cd); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/** 50162306a36Sopenharmony_ci * ice_aq_query_sched_res - query scheduler resource 50262306a36Sopenharmony_ci * @hw: pointer to the HW struct 50362306a36Sopenharmony_ci * @buf_size: buffer size in bytes 50462306a36Sopenharmony_ci * @buf: pointer to buffer 50562306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 50662306a36Sopenharmony_ci * 50762306a36Sopenharmony_ci * Query scheduler resource allocation (0x0412) 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_cistatic int 51062306a36Sopenharmony_ciice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size, 51162306a36Sopenharmony_ci struct ice_aqc_query_txsched_res_resp *buf, 51262306a36Sopenharmony_ci struct ice_sq_cd *cd) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct ice_aq_desc desc; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_sched_res); 51762306a36Sopenharmony_ci return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/** 52162306a36Sopenharmony_ci * ice_sched_suspend_resume_elems - suspend or resume HW nodes 52262306a36Sopenharmony_ci * @hw: pointer to the HW struct 52362306a36Sopenharmony_ci * @num_nodes: number of nodes 52462306a36Sopenharmony_ci * @node_teids: array of node teids to be suspended or resumed 52562306a36Sopenharmony_ci * @suspend: true means suspend / false means resume 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * This function suspends or resumes HW nodes 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_ciint 53062306a36Sopenharmony_ciice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids, 53162306a36Sopenharmony_ci bool suspend) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci u16 i, buf_size, num_elem_ret = 0; 53462306a36Sopenharmony_ci __le32 *buf; 53562306a36Sopenharmony_ci int status; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci buf_size = sizeof(*buf) * num_nodes; 53862306a36Sopenharmony_ci buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL); 53962306a36Sopenharmony_ci if (!buf) 54062306a36Sopenharmony_ci return -ENOMEM; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci for (i = 0; i < num_nodes; i++) 54362306a36Sopenharmony_ci buf[i] = cpu_to_le32(node_teids[i]); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (suspend) 54662306a36Sopenharmony_ci status = ice_aq_suspend_sched_elems(hw, num_nodes, buf, 54762306a36Sopenharmony_ci buf_size, &num_elem_ret, 54862306a36Sopenharmony_ci NULL); 54962306a36Sopenharmony_ci else 55062306a36Sopenharmony_ci status = ice_aq_resume_sched_elems(hw, num_nodes, buf, 55162306a36Sopenharmony_ci buf_size, &num_elem_ret, 55262306a36Sopenharmony_ci NULL); 55362306a36Sopenharmony_ci if (status || num_elem_ret != num_nodes) 55462306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "suspend/resume failed\n"); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), buf); 55762306a36Sopenharmony_ci return status; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/** 56162306a36Sopenharmony_ci * ice_alloc_lan_q_ctx - allocate LAN queue contexts for the given VSI and TC 56262306a36Sopenharmony_ci * @hw: pointer to the HW struct 56362306a36Sopenharmony_ci * @vsi_handle: VSI handle 56462306a36Sopenharmony_ci * @tc: TC number 56562306a36Sopenharmony_ci * @new_numqs: number of queues 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_cistatic int 56862306a36Sopenharmony_ciice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct ice_vsi_ctx *vsi_ctx; 57162306a36Sopenharmony_ci struct ice_q_ctx *q_ctx; 57262306a36Sopenharmony_ci u16 idx; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 57562306a36Sopenharmony_ci if (!vsi_ctx) 57662306a36Sopenharmony_ci return -EINVAL; 57762306a36Sopenharmony_ci /* allocate LAN queue contexts */ 57862306a36Sopenharmony_ci if (!vsi_ctx->lan_q_ctx[tc]) { 57962306a36Sopenharmony_ci q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs, 58062306a36Sopenharmony_ci sizeof(*q_ctx), GFP_KERNEL); 58162306a36Sopenharmony_ci if (!q_ctx) 58262306a36Sopenharmony_ci return -ENOMEM; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci for (idx = 0; idx < new_numqs; idx++) { 58562306a36Sopenharmony_ci q_ctx[idx].q_handle = ICE_INVAL_Q_HANDLE; 58662306a36Sopenharmony_ci q_ctx[idx].q_teid = ICE_INVAL_TEID; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci vsi_ctx->lan_q_ctx[tc] = q_ctx; 59062306a36Sopenharmony_ci vsi_ctx->num_lan_q_entries[tc] = new_numqs; 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci /* num queues are increased, update the queue contexts */ 59462306a36Sopenharmony_ci if (new_numqs > vsi_ctx->num_lan_q_entries[tc]) { 59562306a36Sopenharmony_ci u16 prev_num = vsi_ctx->num_lan_q_entries[tc]; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs, 59862306a36Sopenharmony_ci sizeof(*q_ctx), GFP_KERNEL); 59962306a36Sopenharmony_ci if (!q_ctx) 60062306a36Sopenharmony_ci return -ENOMEM; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci memcpy(q_ctx, vsi_ctx->lan_q_ctx[tc], 60362306a36Sopenharmony_ci prev_num * sizeof(*q_ctx)); 60462306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), vsi_ctx->lan_q_ctx[tc]); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci for (idx = prev_num; idx < new_numqs; idx++) { 60762306a36Sopenharmony_ci q_ctx[idx].q_handle = ICE_INVAL_Q_HANDLE; 60862306a36Sopenharmony_ci q_ctx[idx].q_teid = ICE_INVAL_TEID; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci vsi_ctx->lan_q_ctx[tc] = q_ctx; 61262306a36Sopenharmony_ci vsi_ctx->num_lan_q_entries[tc] = new_numqs; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci return 0; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/** 61862306a36Sopenharmony_ci * ice_alloc_rdma_q_ctx - allocate RDMA queue contexts for the given VSI and TC 61962306a36Sopenharmony_ci * @hw: pointer to the HW struct 62062306a36Sopenharmony_ci * @vsi_handle: VSI handle 62162306a36Sopenharmony_ci * @tc: TC number 62262306a36Sopenharmony_ci * @new_numqs: number of queues 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_cistatic int 62562306a36Sopenharmony_ciice_alloc_rdma_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct ice_vsi_ctx *vsi_ctx; 62862306a36Sopenharmony_ci struct ice_q_ctx *q_ctx; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 63162306a36Sopenharmony_ci if (!vsi_ctx) 63262306a36Sopenharmony_ci return -EINVAL; 63362306a36Sopenharmony_ci /* allocate RDMA queue contexts */ 63462306a36Sopenharmony_ci if (!vsi_ctx->rdma_q_ctx[tc]) { 63562306a36Sopenharmony_ci vsi_ctx->rdma_q_ctx[tc] = devm_kcalloc(ice_hw_to_dev(hw), 63662306a36Sopenharmony_ci new_numqs, 63762306a36Sopenharmony_ci sizeof(*q_ctx), 63862306a36Sopenharmony_ci GFP_KERNEL); 63962306a36Sopenharmony_ci if (!vsi_ctx->rdma_q_ctx[tc]) 64062306a36Sopenharmony_ci return -ENOMEM; 64162306a36Sopenharmony_ci vsi_ctx->num_rdma_q_entries[tc] = new_numqs; 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci /* num queues are increased, update the queue contexts */ 64562306a36Sopenharmony_ci if (new_numqs > vsi_ctx->num_rdma_q_entries[tc]) { 64662306a36Sopenharmony_ci u16 prev_num = vsi_ctx->num_rdma_q_entries[tc]; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs, 64962306a36Sopenharmony_ci sizeof(*q_ctx), GFP_KERNEL); 65062306a36Sopenharmony_ci if (!q_ctx) 65162306a36Sopenharmony_ci return -ENOMEM; 65262306a36Sopenharmony_ci memcpy(q_ctx, vsi_ctx->rdma_q_ctx[tc], 65362306a36Sopenharmony_ci prev_num * sizeof(*q_ctx)); 65462306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), vsi_ctx->rdma_q_ctx[tc]); 65562306a36Sopenharmony_ci vsi_ctx->rdma_q_ctx[tc] = q_ctx; 65662306a36Sopenharmony_ci vsi_ctx->num_rdma_q_entries[tc] = new_numqs; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci/** 66262306a36Sopenharmony_ci * ice_aq_rl_profile - performs a rate limiting task 66362306a36Sopenharmony_ci * @hw: pointer to the HW struct 66462306a36Sopenharmony_ci * @opcode: opcode for add, query, or remove profile(s) 66562306a36Sopenharmony_ci * @num_profiles: the number of profiles 66662306a36Sopenharmony_ci * @buf: pointer to buffer 66762306a36Sopenharmony_ci * @buf_size: buffer size in bytes 66862306a36Sopenharmony_ci * @num_processed: number of processed add or remove profile(s) to return 66962306a36Sopenharmony_ci * @cd: pointer to command details structure 67062306a36Sopenharmony_ci * 67162306a36Sopenharmony_ci * RL profile function to add, query, or remove profile(s) 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_cistatic int 67462306a36Sopenharmony_ciice_aq_rl_profile(struct ice_hw *hw, enum ice_adminq_opc opcode, 67562306a36Sopenharmony_ci u16 num_profiles, struct ice_aqc_rl_profile_elem *buf, 67662306a36Sopenharmony_ci u16 buf_size, u16 *num_processed, struct ice_sq_cd *cd) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct ice_aqc_rl_profile *cmd; 67962306a36Sopenharmony_ci struct ice_aq_desc desc; 68062306a36Sopenharmony_ci int status; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci cmd = &desc.params.rl_profile; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, opcode); 68562306a36Sopenharmony_ci desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 68662306a36Sopenharmony_ci cmd->num_profiles = cpu_to_le16(num_profiles); 68762306a36Sopenharmony_ci status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 68862306a36Sopenharmony_ci if (!status && num_processed) 68962306a36Sopenharmony_ci *num_processed = le16_to_cpu(cmd->num_processed); 69062306a36Sopenharmony_ci return status; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/** 69462306a36Sopenharmony_ci * ice_aq_add_rl_profile - adds rate limiting profile(s) 69562306a36Sopenharmony_ci * @hw: pointer to the HW struct 69662306a36Sopenharmony_ci * @num_profiles: the number of profile(s) to be add 69762306a36Sopenharmony_ci * @buf: pointer to buffer 69862306a36Sopenharmony_ci * @buf_size: buffer size in bytes 69962306a36Sopenharmony_ci * @num_profiles_added: total number of profiles added to return 70062306a36Sopenharmony_ci * @cd: pointer to command details structure 70162306a36Sopenharmony_ci * 70262306a36Sopenharmony_ci * Add RL profile (0x0410) 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_cistatic int 70562306a36Sopenharmony_ciice_aq_add_rl_profile(struct ice_hw *hw, u16 num_profiles, 70662306a36Sopenharmony_ci struct ice_aqc_rl_profile_elem *buf, u16 buf_size, 70762306a36Sopenharmony_ci u16 *num_profiles_added, struct ice_sq_cd *cd) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci return ice_aq_rl_profile(hw, ice_aqc_opc_add_rl_profiles, num_profiles, 71062306a36Sopenharmony_ci buf, buf_size, num_profiles_added, cd); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci/** 71462306a36Sopenharmony_ci * ice_aq_remove_rl_profile - removes RL profile(s) 71562306a36Sopenharmony_ci * @hw: pointer to the HW struct 71662306a36Sopenharmony_ci * @num_profiles: the number of profile(s) to remove 71762306a36Sopenharmony_ci * @buf: pointer to buffer 71862306a36Sopenharmony_ci * @buf_size: buffer size in bytes 71962306a36Sopenharmony_ci * @num_profiles_removed: total number of profiles removed to return 72062306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL 72162306a36Sopenharmony_ci * 72262306a36Sopenharmony_ci * Remove RL profile (0x0415) 72362306a36Sopenharmony_ci */ 72462306a36Sopenharmony_cistatic int 72562306a36Sopenharmony_ciice_aq_remove_rl_profile(struct ice_hw *hw, u16 num_profiles, 72662306a36Sopenharmony_ci struct ice_aqc_rl_profile_elem *buf, u16 buf_size, 72762306a36Sopenharmony_ci u16 *num_profiles_removed, struct ice_sq_cd *cd) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci return ice_aq_rl_profile(hw, ice_aqc_opc_remove_rl_profiles, 73062306a36Sopenharmony_ci num_profiles, buf, buf_size, 73162306a36Sopenharmony_ci num_profiles_removed, cd); 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci/** 73562306a36Sopenharmony_ci * ice_sched_del_rl_profile - remove RL profile 73662306a36Sopenharmony_ci * @hw: pointer to the HW struct 73762306a36Sopenharmony_ci * @rl_info: rate limit profile information 73862306a36Sopenharmony_ci * 73962306a36Sopenharmony_ci * If the profile ID is not referenced anymore, it removes profile ID with 74062306a36Sopenharmony_ci * its associated parameters from HW DB,and locally. The caller needs to 74162306a36Sopenharmony_ci * hold scheduler lock. 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_cistatic int 74462306a36Sopenharmony_ciice_sched_del_rl_profile(struct ice_hw *hw, 74562306a36Sopenharmony_ci struct ice_aqc_rl_profile_info *rl_info) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct ice_aqc_rl_profile_elem *buf; 74862306a36Sopenharmony_ci u16 num_profiles_removed; 74962306a36Sopenharmony_ci u16 num_profiles = 1; 75062306a36Sopenharmony_ci int status; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (rl_info->prof_id_ref != 0) 75362306a36Sopenharmony_ci return -EBUSY; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* Safe to remove profile ID */ 75662306a36Sopenharmony_ci buf = &rl_info->profile; 75762306a36Sopenharmony_ci status = ice_aq_remove_rl_profile(hw, num_profiles, buf, sizeof(*buf), 75862306a36Sopenharmony_ci &num_profiles_removed, NULL); 75962306a36Sopenharmony_ci if (status || num_profiles_removed != num_profiles) 76062306a36Sopenharmony_ci return -EIO; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* Delete stale entry now */ 76362306a36Sopenharmony_ci list_del(&rl_info->list_entry); 76462306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), rl_info); 76562306a36Sopenharmony_ci return status; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/** 76962306a36Sopenharmony_ci * ice_sched_clear_rl_prof - clears RL prof entries 77062306a36Sopenharmony_ci * @pi: port information structure 77162306a36Sopenharmony_ci * 77262306a36Sopenharmony_ci * This function removes all RL profile from HW as well as from SW DB. 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_cistatic void ice_sched_clear_rl_prof(struct ice_port_info *pi) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci u16 ln; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci for (ln = 0; ln < pi->hw->num_tx_sched_layers; ln++) { 77962306a36Sopenharmony_ci struct ice_aqc_rl_profile_info *rl_prof_elem; 78062306a36Sopenharmony_ci struct ice_aqc_rl_profile_info *rl_prof_tmp; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci list_for_each_entry_safe(rl_prof_elem, rl_prof_tmp, 78362306a36Sopenharmony_ci &pi->rl_prof_list[ln], list_entry) { 78462306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 78562306a36Sopenharmony_ci int status; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci rl_prof_elem->prof_id_ref = 0; 78862306a36Sopenharmony_ci status = ice_sched_del_rl_profile(hw, rl_prof_elem); 78962306a36Sopenharmony_ci if (status) { 79062306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n"); 79162306a36Sopenharmony_ci /* On error, free mem required */ 79262306a36Sopenharmony_ci list_del(&rl_prof_elem->list_entry); 79362306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), rl_prof_elem); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci/** 80062306a36Sopenharmony_ci * ice_sched_clear_agg - clears the aggregator related information 80162306a36Sopenharmony_ci * @hw: pointer to the hardware structure 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * This function removes aggregator list and free up aggregator related memory 80462306a36Sopenharmony_ci * previously allocated. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_civoid ice_sched_clear_agg(struct ice_hw *hw) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 80962306a36Sopenharmony_ci struct ice_sched_agg_info *atmp; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci list_for_each_entry_safe(agg_info, atmp, &hw->agg_list, list_entry) { 81262306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info; 81362306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *vtmp; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci list_for_each_entry_safe(agg_vsi_info, vtmp, 81662306a36Sopenharmony_ci &agg_info->agg_vsi_list, list_entry) { 81762306a36Sopenharmony_ci list_del(&agg_vsi_info->list_entry); 81862306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), agg_vsi_info); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci list_del(&agg_info->list_entry); 82162306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), agg_info); 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci/** 82662306a36Sopenharmony_ci * ice_sched_clear_tx_topo - clears the scheduler tree nodes 82762306a36Sopenharmony_ci * @pi: port information structure 82862306a36Sopenharmony_ci * 82962306a36Sopenharmony_ci * This function removes all the nodes from HW as well as from SW DB. 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_cistatic void ice_sched_clear_tx_topo(struct ice_port_info *pi) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci if (!pi) 83462306a36Sopenharmony_ci return; 83562306a36Sopenharmony_ci /* remove RL profiles related lists */ 83662306a36Sopenharmony_ci ice_sched_clear_rl_prof(pi); 83762306a36Sopenharmony_ci if (pi->root) { 83862306a36Sopenharmony_ci ice_free_sched_node(pi, pi->root); 83962306a36Sopenharmony_ci pi->root = NULL; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci/** 84462306a36Sopenharmony_ci * ice_sched_clear_port - clear the scheduler elements from SW DB for a port 84562306a36Sopenharmony_ci * @pi: port information structure 84662306a36Sopenharmony_ci * 84762306a36Sopenharmony_ci * Cleanup scheduling elements from SW DB 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_civoid ice_sched_clear_port(struct ice_port_info *pi) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY) 85262306a36Sopenharmony_ci return; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci pi->port_state = ICE_SCHED_PORT_STATE_INIT; 85562306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 85662306a36Sopenharmony_ci ice_sched_clear_tx_topo(pi); 85762306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 85862306a36Sopenharmony_ci mutex_destroy(&pi->sched_lock); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci/** 86262306a36Sopenharmony_ci * ice_sched_cleanup_all - cleanup scheduler elements from SW DB for all ports 86362306a36Sopenharmony_ci * @hw: pointer to the HW struct 86462306a36Sopenharmony_ci * 86562306a36Sopenharmony_ci * Cleanup scheduling elements from SW DB for all the ports 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_civoid ice_sched_cleanup_all(struct ice_hw *hw) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci if (!hw) 87062306a36Sopenharmony_ci return; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), hw->layer_info); 87362306a36Sopenharmony_ci hw->layer_info = NULL; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci ice_sched_clear_port(hw->port_info); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci hw->num_tx_sched_layers = 0; 87862306a36Sopenharmony_ci hw->num_tx_sched_phys_layers = 0; 87962306a36Sopenharmony_ci hw->flattened_layers = 0; 88062306a36Sopenharmony_ci hw->max_cgds = 0; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci/** 88462306a36Sopenharmony_ci * ice_sched_add_elems - add nodes to HW and SW DB 88562306a36Sopenharmony_ci * @pi: port information structure 88662306a36Sopenharmony_ci * @tc_node: pointer to the branch node 88762306a36Sopenharmony_ci * @parent: pointer to the parent node 88862306a36Sopenharmony_ci * @layer: layer number to add nodes 88962306a36Sopenharmony_ci * @num_nodes: number of nodes 89062306a36Sopenharmony_ci * @num_nodes_added: pointer to num nodes added 89162306a36Sopenharmony_ci * @first_node_teid: if new nodes are added then return the TEID of first node 89262306a36Sopenharmony_ci * @prealloc_nodes: preallocated nodes struct for software DB 89362306a36Sopenharmony_ci * 89462306a36Sopenharmony_ci * This function add nodes to HW as well as to SW DB for a given layer 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ciint 89762306a36Sopenharmony_ciice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node, 89862306a36Sopenharmony_ci struct ice_sched_node *parent, u8 layer, u16 num_nodes, 89962306a36Sopenharmony_ci u16 *num_nodes_added, u32 *first_node_teid, 90062306a36Sopenharmony_ci struct ice_sched_node **prealloc_nodes) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci struct ice_sched_node *prev, *new_node; 90362306a36Sopenharmony_ci struct ice_aqc_add_elem *buf; 90462306a36Sopenharmony_ci u16 i, num_groups_added = 0; 90562306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 90662306a36Sopenharmony_ci size_t buf_size; 90762306a36Sopenharmony_ci int status = 0; 90862306a36Sopenharmony_ci u32 teid; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci buf_size = struct_size(buf, generic, num_nodes); 91162306a36Sopenharmony_ci buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL); 91262306a36Sopenharmony_ci if (!buf) 91362306a36Sopenharmony_ci return -ENOMEM; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci buf->hdr.parent_teid = parent->info.node_teid; 91662306a36Sopenharmony_ci buf->hdr.num_elems = cpu_to_le16(num_nodes); 91762306a36Sopenharmony_ci for (i = 0; i < num_nodes; i++) { 91862306a36Sopenharmony_ci buf->generic[i].parent_teid = parent->info.node_teid; 91962306a36Sopenharmony_ci buf->generic[i].data.elem_type = ICE_AQC_ELEM_TYPE_SE_GENERIC; 92062306a36Sopenharmony_ci buf->generic[i].data.valid_sections = 92162306a36Sopenharmony_ci ICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR | 92262306a36Sopenharmony_ci ICE_AQC_ELEM_VALID_EIR; 92362306a36Sopenharmony_ci buf->generic[i].data.generic = 0; 92462306a36Sopenharmony_ci buf->generic[i].data.cir_bw.bw_profile_idx = 92562306a36Sopenharmony_ci cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID); 92662306a36Sopenharmony_ci buf->generic[i].data.cir_bw.bw_alloc = 92762306a36Sopenharmony_ci cpu_to_le16(ICE_SCHED_DFLT_BW_WT); 92862306a36Sopenharmony_ci buf->generic[i].data.eir_bw.bw_profile_idx = 92962306a36Sopenharmony_ci cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID); 93062306a36Sopenharmony_ci buf->generic[i].data.eir_bw.bw_alloc = 93162306a36Sopenharmony_ci cpu_to_le16(ICE_SCHED_DFLT_BW_WT); 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci status = ice_aq_add_sched_elems(hw, 1, buf, buf_size, 93562306a36Sopenharmony_ci &num_groups_added, NULL); 93662306a36Sopenharmony_ci if (status || num_groups_added != 1) { 93762306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "add node failed FW Error %d\n", 93862306a36Sopenharmony_ci hw->adminq.sq_last_status); 93962306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), buf); 94062306a36Sopenharmony_ci return -EIO; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci *num_nodes_added = num_nodes; 94462306a36Sopenharmony_ci /* add nodes to the SW DB */ 94562306a36Sopenharmony_ci for (i = 0; i < num_nodes; i++) { 94662306a36Sopenharmony_ci if (prealloc_nodes) 94762306a36Sopenharmony_ci status = ice_sched_add_node(pi, layer, &buf->generic[i], prealloc_nodes[i]); 94862306a36Sopenharmony_ci else 94962306a36Sopenharmony_ci status = ice_sched_add_node(pi, layer, &buf->generic[i], NULL); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (status) { 95262306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "add nodes in SW DB failed status =%d\n", 95362306a36Sopenharmony_ci status); 95462306a36Sopenharmony_ci break; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci teid = le32_to_cpu(buf->generic[i].node_teid); 95862306a36Sopenharmony_ci new_node = ice_sched_find_node_by_teid(parent, teid); 95962306a36Sopenharmony_ci if (!new_node) { 96062306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "Node is missing for teid =%d\n", teid); 96162306a36Sopenharmony_ci break; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci new_node->sibling = NULL; 96562306a36Sopenharmony_ci new_node->tc_num = tc_node->tc_num; 96662306a36Sopenharmony_ci new_node->tx_weight = ICE_SCHED_DFLT_BW_WT; 96762306a36Sopenharmony_ci new_node->tx_share = ICE_SCHED_DFLT_BW; 96862306a36Sopenharmony_ci new_node->tx_max = ICE_SCHED_DFLT_BW; 96962306a36Sopenharmony_ci new_node->name = kzalloc(SCHED_NODE_NAME_MAX_LEN, GFP_KERNEL); 97062306a36Sopenharmony_ci if (!new_node->name) 97162306a36Sopenharmony_ci return -ENOMEM; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci status = xa_alloc(&pi->sched_node_ids, &new_node->id, NULL, XA_LIMIT(0, UINT_MAX), 97462306a36Sopenharmony_ci GFP_KERNEL); 97562306a36Sopenharmony_ci if (status) { 97662306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "xa_alloc failed for sched node status =%d\n", 97762306a36Sopenharmony_ci status); 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci snprintf(new_node->name, SCHED_NODE_NAME_MAX_LEN, "node_%u", new_node->id); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* add it to previous node sibling pointer */ 98462306a36Sopenharmony_ci /* Note: siblings are not linked across branches */ 98562306a36Sopenharmony_ci prev = ice_sched_get_first_node(pi, tc_node, layer); 98662306a36Sopenharmony_ci if (prev && prev != new_node) { 98762306a36Sopenharmony_ci while (prev->sibling) 98862306a36Sopenharmony_ci prev = prev->sibling; 98962306a36Sopenharmony_ci prev->sibling = new_node; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* initialize the sibling head */ 99362306a36Sopenharmony_ci if (!pi->sib_head[tc_node->tc_num][layer]) 99462306a36Sopenharmony_ci pi->sib_head[tc_node->tc_num][layer] = new_node; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (i == 0) 99762306a36Sopenharmony_ci *first_node_teid = teid; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), buf); 100162306a36Sopenharmony_ci return status; 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci/** 100562306a36Sopenharmony_ci * ice_sched_add_nodes_to_hw_layer - Add nodes to HW layer 100662306a36Sopenharmony_ci * @pi: port information structure 100762306a36Sopenharmony_ci * @tc_node: pointer to TC node 100862306a36Sopenharmony_ci * @parent: pointer to parent node 100962306a36Sopenharmony_ci * @layer: layer number to add nodes 101062306a36Sopenharmony_ci * @num_nodes: number of nodes to be added 101162306a36Sopenharmony_ci * @first_node_teid: pointer to the first node TEID 101262306a36Sopenharmony_ci * @num_nodes_added: pointer to number of nodes added 101362306a36Sopenharmony_ci * 101462306a36Sopenharmony_ci * Add nodes into specific HW layer. 101562306a36Sopenharmony_ci */ 101662306a36Sopenharmony_cistatic int 101762306a36Sopenharmony_ciice_sched_add_nodes_to_hw_layer(struct ice_port_info *pi, 101862306a36Sopenharmony_ci struct ice_sched_node *tc_node, 101962306a36Sopenharmony_ci struct ice_sched_node *parent, u8 layer, 102062306a36Sopenharmony_ci u16 num_nodes, u32 *first_node_teid, 102162306a36Sopenharmony_ci u16 *num_nodes_added) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci u16 max_child_nodes; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci *num_nodes_added = 0; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (!num_nodes) 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (!parent || layer < pi->hw->sw_entry_point_layer) 103162306a36Sopenharmony_ci return -EINVAL; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* max children per node per layer */ 103462306a36Sopenharmony_ci max_child_nodes = pi->hw->max_children[parent->tx_sched_layer]; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* current number of children + required nodes exceed max children */ 103762306a36Sopenharmony_ci if ((parent->num_children + num_nodes) > max_child_nodes) { 103862306a36Sopenharmony_ci /* Fail if the parent is a TC node */ 103962306a36Sopenharmony_ci if (parent == tc_node) 104062306a36Sopenharmony_ci return -EIO; 104162306a36Sopenharmony_ci return -ENOSPC; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci return ice_sched_add_elems(pi, tc_node, parent, layer, num_nodes, 104562306a36Sopenharmony_ci num_nodes_added, first_node_teid, NULL); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci/** 104962306a36Sopenharmony_ci * ice_sched_add_nodes_to_layer - Add nodes to a given layer 105062306a36Sopenharmony_ci * @pi: port information structure 105162306a36Sopenharmony_ci * @tc_node: pointer to TC node 105262306a36Sopenharmony_ci * @parent: pointer to parent node 105362306a36Sopenharmony_ci * @layer: layer number to add nodes 105462306a36Sopenharmony_ci * @num_nodes: number of nodes to be added 105562306a36Sopenharmony_ci * @first_node_teid: pointer to the first node TEID 105662306a36Sopenharmony_ci * @num_nodes_added: pointer to number of nodes added 105762306a36Sopenharmony_ci * 105862306a36Sopenharmony_ci * This function add nodes to a given layer. 105962306a36Sopenharmony_ci */ 106062306a36Sopenharmony_ciint 106162306a36Sopenharmony_ciice_sched_add_nodes_to_layer(struct ice_port_info *pi, 106262306a36Sopenharmony_ci struct ice_sched_node *tc_node, 106362306a36Sopenharmony_ci struct ice_sched_node *parent, u8 layer, 106462306a36Sopenharmony_ci u16 num_nodes, u32 *first_node_teid, 106562306a36Sopenharmony_ci u16 *num_nodes_added) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci u32 *first_teid_ptr = first_node_teid; 106862306a36Sopenharmony_ci u16 new_num_nodes = num_nodes; 106962306a36Sopenharmony_ci int status = 0; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci *num_nodes_added = 0; 107262306a36Sopenharmony_ci while (*num_nodes_added < num_nodes) { 107362306a36Sopenharmony_ci u16 max_child_nodes, num_added = 0; 107462306a36Sopenharmony_ci u32 temp; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci status = ice_sched_add_nodes_to_hw_layer(pi, tc_node, parent, 107762306a36Sopenharmony_ci layer, new_num_nodes, 107862306a36Sopenharmony_ci first_teid_ptr, 107962306a36Sopenharmony_ci &num_added); 108062306a36Sopenharmony_ci if (!status) 108162306a36Sopenharmony_ci *num_nodes_added += num_added; 108262306a36Sopenharmony_ci /* added more nodes than requested ? */ 108362306a36Sopenharmony_ci if (*num_nodes_added > num_nodes) { 108462306a36Sopenharmony_ci ice_debug(pi->hw, ICE_DBG_SCHED, "added extra nodes %d %d\n", num_nodes, 108562306a36Sopenharmony_ci *num_nodes_added); 108662306a36Sopenharmony_ci status = -EIO; 108762306a36Sopenharmony_ci break; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci /* break if all the nodes are added successfully */ 109062306a36Sopenharmony_ci if (!status && (*num_nodes_added == num_nodes)) 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci /* break if the error is not max limit */ 109362306a36Sopenharmony_ci if (status && status != -ENOSPC) 109462306a36Sopenharmony_ci break; 109562306a36Sopenharmony_ci /* Exceeded the max children */ 109662306a36Sopenharmony_ci max_child_nodes = pi->hw->max_children[parent->tx_sched_layer]; 109762306a36Sopenharmony_ci /* utilize all the spaces if the parent is not full */ 109862306a36Sopenharmony_ci if (parent->num_children < max_child_nodes) { 109962306a36Sopenharmony_ci new_num_nodes = max_child_nodes - parent->num_children; 110062306a36Sopenharmony_ci } else { 110162306a36Sopenharmony_ci /* This parent is full, try the next sibling */ 110262306a36Sopenharmony_ci parent = parent->sibling; 110362306a36Sopenharmony_ci /* Don't modify the first node TEID memory if the 110462306a36Sopenharmony_ci * first node was added already in the above call. 110562306a36Sopenharmony_ci * Instead send some temp memory for all other 110662306a36Sopenharmony_ci * recursive calls. 110762306a36Sopenharmony_ci */ 110862306a36Sopenharmony_ci if (num_added) 110962306a36Sopenharmony_ci first_teid_ptr = &temp; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci new_num_nodes = num_nodes - *num_nodes_added; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci return status; 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci/** 111862306a36Sopenharmony_ci * ice_sched_get_qgrp_layer - get the current queue group layer number 111962306a36Sopenharmony_ci * @hw: pointer to the HW struct 112062306a36Sopenharmony_ci * 112162306a36Sopenharmony_ci * This function returns the current queue group layer number 112262306a36Sopenharmony_ci */ 112362306a36Sopenharmony_cistatic u8 ice_sched_get_qgrp_layer(struct ice_hw *hw) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci /* It's always total layers - 1, the array is 0 relative so -2 */ 112662306a36Sopenharmony_ci return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci/** 113062306a36Sopenharmony_ci * ice_sched_get_vsi_layer - get the current VSI layer number 113162306a36Sopenharmony_ci * @hw: pointer to the HW struct 113262306a36Sopenharmony_ci * 113362306a36Sopenharmony_ci * This function returns the current VSI layer number 113462306a36Sopenharmony_ci */ 113562306a36Sopenharmony_ciu8 ice_sched_get_vsi_layer(struct ice_hw *hw) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci /* Num Layers VSI layer 113862306a36Sopenharmony_ci * 9 6 113962306a36Sopenharmony_ci * 7 4 114062306a36Sopenharmony_ci * 5 or less sw_entry_point_layer 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_ci /* calculate the VSI layer based on number of layers. */ 114362306a36Sopenharmony_ci if (hw->num_tx_sched_layers > ICE_VSI_LAYER_OFFSET + 1) { 114462306a36Sopenharmony_ci u8 layer = hw->num_tx_sched_layers - ICE_VSI_LAYER_OFFSET; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (layer > hw->sw_entry_point_layer) 114762306a36Sopenharmony_ci return layer; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci return hw->sw_entry_point_layer; 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci/** 115362306a36Sopenharmony_ci * ice_sched_get_agg_layer - get the current aggregator layer number 115462306a36Sopenharmony_ci * @hw: pointer to the HW struct 115562306a36Sopenharmony_ci * 115662306a36Sopenharmony_ci * This function returns the current aggregator layer number 115762306a36Sopenharmony_ci */ 115862306a36Sopenharmony_ciu8 ice_sched_get_agg_layer(struct ice_hw *hw) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci /* Num Layers aggregator layer 116162306a36Sopenharmony_ci * 9 4 116262306a36Sopenharmony_ci * 7 or less sw_entry_point_layer 116362306a36Sopenharmony_ci */ 116462306a36Sopenharmony_ci /* calculate the aggregator layer based on number of layers. */ 116562306a36Sopenharmony_ci if (hw->num_tx_sched_layers > ICE_AGG_LAYER_OFFSET + 1) { 116662306a36Sopenharmony_ci u8 layer = hw->num_tx_sched_layers - ICE_AGG_LAYER_OFFSET; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (layer > hw->sw_entry_point_layer) 116962306a36Sopenharmony_ci return layer; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci return hw->sw_entry_point_layer; 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci/** 117562306a36Sopenharmony_ci * ice_rm_dflt_leaf_node - remove the default leaf node in the tree 117662306a36Sopenharmony_ci * @pi: port information structure 117762306a36Sopenharmony_ci * 117862306a36Sopenharmony_ci * This function removes the leaf node that was created by the FW 117962306a36Sopenharmony_ci * during initialization 118062306a36Sopenharmony_ci */ 118162306a36Sopenharmony_cistatic void ice_rm_dflt_leaf_node(struct ice_port_info *pi) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci struct ice_sched_node *node; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci node = pi->root; 118662306a36Sopenharmony_ci while (node) { 118762306a36Sopenharmony_ci if (!node->num_children) 118862306a36Sopenharmony_ci break; 118962306a36Sopenharmony_ci node = node->children[0]; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci if (node && node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) { 119262306a36Sopenharmony_ci u32 teid = le32_to_cpu(node->info.node_teid); 119362306a36Sopenharmony_ci int status; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci /* remove the default leaf node */ 119662306a36Sopenharmony_ci status = ice_sched_remove_elems(pi->hw, node->parent, 1, &teid); 119762306a36Sopenharmony_ci if (!status) 119862306a36Sopenharmony_ci ice_free_sched_node(pi, node); 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci} 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci/** 120362306a36Sopenharmony_ci * ice_sched_rm_dflt_nodes - free the default nodes in the tree 120462306a36Sopenharmony_ci * @pi: port information structure 120562306a36Sopenharmony_ci * 120662306a36Sopenharmony_ci * This function frees all the nodes except root and TC that were created by 120762306a36Sopenharmony_ci * the FW during initialization 120862306a36Sopenharmony_ci */ 120962306a36Sopenharmony_cistatic void ice_sched_rm_dflt_nodes(struct ice_port_info *pi) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci struct ice_sched_node *node; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci ice_rm_dflt_leaf_node(pi); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci /* remove the default nodes except TC and root nodes */ 121662306a36Sopenharmony_ci node = pi->root; 121762306a36Sopenharmony_ci while (node) { 121862306a36Sopenharmony_ci if (node->tx_sched_layer >= pi->hw->sw_entry_point_layer && 121962306a36Sopenharmony_ci node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC && 122062306a36Sopenharmony_ci node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT) { 122162306a36Sopenharmony_ci ice_free_sched_node(pi, node); 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (!node->num_children) 122662306a36Sopenharmony_ci break; 122762306a36Sopenharmony_ci node = node->children[0]; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/** 123262306a36Sopenharmony_ci * ice_sched_init_port - Initialize scheduler by querying information from FW 123362306a36Sopenharmony_ci * @pi: port info structure for the tree to cleanup 123462306a36Sopenharmony_ci * 123562306a36Sopenharmony_ci * This function is the initial call to find the total number of Tx scheduler 123662306a36Sopenharmony_ci * resources, default topology created by firmware and storing the information 123762306a36Sopenharmony_ci * in SW DB. 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ciint ice_sched_init_port(struct ice_port_info *pi) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci struct ice_aqc_get_topo_elem *buf; 124262306a36Sopenharmony_ci struct ice_hw *hw; 124362306a36Sopenharmony_ci u8 num_branches; 124462306a36Sopenharmony_ci u16 num_elems; 124562306a36Sopenharmony_ci int status; 124662306a36Sopenharmony_ci u8 i, j; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (!pi) 124962306a36Sopenharmony_ci return -EINVAL; 125062306a36Sopenharmony_ci hw = pi->hw; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* Query the Default Topology from FW */ 125362306a36Sopenharmony_ci buf = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL); 125462306a36Sopenharmony_ci if (!buf) 125562306a36Sopenharmony_ci return -ENOMEM; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* Query default scheduling tree topology */ 125862306a36Sopenharmony_ci status = ice_aq_get_dflt_topo(hw, pi->lport, buf, ICE_AQ_MAX_BUF_LEN, 125962306a36Sopenharmony_ci &num_branches, NULL); 126062306a36Sopenharmony_ci if (status) 126162306a36Sopenharmony_ci goto err_init_port; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci /* num_branches should be between 1-8 */ 126462306a36Sopenharmony_ci if (num_branches < 1 || num_branches > ICE_TXSCHED_MAX_BRANCHES) { 126562306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "num_branches unexpected %d\n", 126662306a36Sopenharmony_ci num_branches); 126762306a36Sopenharmony_ci status = -EINVAL; 126862306a36Sopenharmony_ci goto err_init_port; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci /* get the number of elements on the default/first branch */ 127262306a36Sopenharmony_ci num_elems = le16_to_cpu(buf[0].hdr.num_elems); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* num_elems should always be between 1-9 */ 127562306a36Sopenharmony_ci if (num_elems < 1 || num_elems > ICE_AQC_TOPO_MAX_LEVEL_NUM) { 127662306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "num_elems unexpected %d\n", 127762306a36Sopenharmony_ci num_elems); 127862306a36Sopenharmony_ci status = -EINVAL; 127962306a36Sopenharmony_ci goto err_init_port; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci /* If the last node is a leaf node then the index of the queue group 128362306a36Sopenharmony_ci * layer is two less than the number of elements. 128462306a36Sopenharmony_ci */ 128562306a36Sopenharmony_ci if (num_elems > 2 && buf[0].generic[num_elems - 1].data.elem_type == 128662306a36Sopenharmony_ci ICE_AQC_ELEM_TYPE_LEAF) 128762306a36Sopenharmony_ci pi->last_node_teid = 128862306a36Sopenharmony_ci le32_to_cpu(buf[0].generic[num_elems - 2].node_teid); 128962306a36Sopenharmony_ci else 129062306a36Sopenharmony_ci pi->last_node_teid = 129162306a36Sopenharmony_ci le32_to_cpu(buf[0].generic[num_elems - 1].node_teid); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci /* Insert the Tx Sched root node */ 129462306a36Sopenharmony_ci status = ice_sched_add_root_node(pi, &buf[0].generic[0]); 129562306a36Sopenharmony_ci if (status) 129662306a36Sopenharmony_ci goto err_init_port; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* Parse the default tree and cache the information */ 129962306a36Sopenharmony_ci for (i = 0; i < num_branches; i++) { 130062306a36Sopenharmony_ci num_elems = le16_to_cpu(buf[i].hdr.num_elems); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci /* Skip root element as already inserted */ 130362306a36Sopenharmony_ci for (j = 1; j < num_elems; j++) { 130462306a36Sopenharmony_ci /* update the sw entry point */ 130562306a36Sopenharmony_ci if (buf[0].generic[j].data.elem_type == 130662306a36Sopenharmony_ci ICE_AQC_ELEM_TYPE_ENTRY_POINT) 130762306a36Sopenharmony_ci hw->sw_entry_point_layer = j; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci status = ice_sched_add_node(pi, j, &buf[i].generic[j], NULL); 131062306a36Sopenharmony_ci if (status) 131162306a36Sopenharmony_ci goto err_init_port; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci /* Remove the default nodes. */ 131662306a36Sopenharmony_ci if (pi->root) 131762306a36Sopenharmony_ci ice_sched_rm_dflt_nodes(pi); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci /* initialize the port for handling the scheduler tree */ 132062306a36Sopenharmony_ci pi->port_state = ICE_SCHED_PORT_STATE_READY; 132162306a36Sopenharmony_ci mutex_init(&pi->sched_lock); 132262306a36Sopenharmony_ci for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++) 132362306a36Sopenharmony_ci INIT_LIST_HEAD(&pi->rl_prof_list[i]); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cierr_init_port: 132662306a36Sopenharmony_ci if (status && pi->root) { 132762306a36Sopenharmony_ci ice_free_sched_node(pi, pi->root); 132862306a36Sopenharmony_ci pi->root = NULL; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci kfree(buf); 133262306a36Sopenharmony_ci return status; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci/** 133662306a36Sopenharmony_ci * ice_sched_query_res_alloc - query the FW for num of logical sched layers 133762306a36Sopenharmony_ci * @hw: pointer to the HW struct 133862306a36Sopenharmony_ci * 133962306a36Sopenharmony_ci * query FW for allocated scheduler resources and store in HW struct 134062306a36Sopenharmony_ci */ 134162306a36Sopenharmony_ciint ice_sched_query_res_alloc(struct ice_hw *hw) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci struct ice_aqc_query_txsched_res_resp *buf; 134462306a36Sopenharmony_ci __le16 max_sibl; 134562306a36Sopenharmony_ci int status = 0; 134662306a36Sopenharmony_ci u16 i; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (hw->layer_info) 134962306a36Sopenharmony_ci return status; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci buf = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*buf), GFP_KERNEL); 135262306a36Sopenharmony_ci if (!buf) 135362306a36Sopenharmony_ci return -ENOMEM; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci status = ice_aq_query_sched_res(hw, sizeof(*buf), buf, NULL); 135662306a36Sopenharmony_ci if (status) 135762306a36Sopenharmony_ci goto sched_query_out; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci hw->num_tx_sched_layers = le16_to_cpu(buf->sched_props.logical_levels); 136062306a36Sopenharmony_ci hw->num_tx_sched_phys_layers = 136162306a36Sopenharmony_ci le16_to_cpu(buf->sched_props.phys_levels); 136262306a36Sopenharmony_ci hw->flattened_layers = buf->sched_props.flattening_bitmap; 136362306a36Sopenharmony_ci hw->max_cgds = buf->sched_props.max_pf_cgds; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci /* max sibling group size of current layer refers to the max children 136662306a36Sopenharmony_ci * of the below layer node. 136762306a36Sopenharmony_ci * layer 1 node max children will be layer 2 max sibling group size 136862306a36Sopenharmony_ci * layer 2 node max children will be layer 3 max sibling group size 136962306a36Sopenharmony_ci * and so on. This array will be populated from root (index 0) to 137062306a36Sopenharmony_ci * qgroup layer 7. Leaf node has no children. 137162306a36Sopenharmony_ci */ 137262306a36Sopenharmony_ci for (i = 0; i < hw->num_tx_sched_layers - 1; i++) { 137362306a36Sopenharmony_ci max_sibl = buf->layer_props[i + 1].max_sibl_grp_sz; 137462306a36Sopenharmony_ci hw->max_children[i] = le16_to_cpu(max_sibl); 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci hw->layer_info = devm_kmemdup(ice_hw_to_dev(hw), buf->layer_props, 137862306a36Sopenharmony_ci (hw->num_tx_sched_layers * 137962306a36Sopenharmony_ci sizeof(*hw->layer_info)), 138062306a36Sopenharmony_ci GFP_KERNEL); 138162306a36Sopenharmony_ci if (!hw->layer_info) { 138262306a36Sopenharmony_ci status = -ENOMEM; 138362306a36Sopenharmony_ci goto sched_query_out; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cisched_query_out: 138762306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), buf); 138862306a36Sopenharmony_ci return status; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci/** 139262306a36Sopenharmony_ci * ice_sched_get_psm_clk_freq - determine the PSM clock frequency 139362306a36Sopenharmony_ci * @hw: pointer to the HW struct 139462306a36Sopenharmony_ci * 139562306a36Sopenharmony_ci * Determine the PSM clock frequency and store in HW struct 139662306a36Sopenharmony_ci */ 139762306a36Sopenharmony_civoid ice_sched_get_psm_clk_freq(struct ice_hw *hw) 139862306a36Sopenharmony_ci{ 139962306a36Sopenharmony_ci u32 val, clk_src; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci val = rd32(hw, GLGEN_CLKSTAT_SRC); 140262306a36Sopenharmony_ci clk_src = (val & GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M) >> 140362306a36Sopenharmony_ci GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_S; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci#define PSM_CLK_SRC_367_MHZ 0x0 140662306a36Sopenharmony_ci#define PSM_CLK_SRC_416_MHZ 0x1 140762306a36Sopenharmony_ci#define PSM_CLK_SRC_446_MHZ 0x2 140862306a36Sopenharmony_ci#define PSM_CLK_SRC_390_MHZ 0x3 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci switch (clk_src) { 141162306a36Sopenharmony_ci case PSM_CLK_SRC_367_MHZ: 141262306a36Sopenharmony_ci hw->psm_clk_freq = ICE_PSM_CLK_367MHZ_IN_HZ; 141362306a36Sopenharmony_ci break; 141462306a36Sopenharmony_ci case PSM_CLK_SRC_416_MHZ: 141562306a36Sopenharmony_ci hw->psm_clk_freq = ICE_PSM_CLK_416MHZ_IN_HZ; 141662306a36Sopenharmony_ci break; 141762306a36Sopenharmony_ci case PSM_CLK_SRC_446_MHZ: 141862306a36Sopenharmony_ci hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ; 141962306a36Sopenharmony_ci break; 142062306a36Sopenharmony_ci case PSM_CLK_SRC_390_MHZ: 142162306a36Sopenharmony_ci hw->psm_clk_freq = ICE_PSM_CLK_390MHZ_IN_HZ; 142262306a36Sopenharmony_ci break; 142362306a36Sopenharmony_ci default: 142462306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "PSM clk_src unexpected %u\n", 142562306a36Sopenharmony_ci clk_src); 142662306a36Sopenharmony_ci /* fall back to a safe default */ 142762306a36Sopenharmony_ci hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci} 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci/** 143262306a36Sopenharmony_ci * ice_sched_find_node_in_subtree - Find node in part of base node subtree 143362306a36Sopenharmony_ci * @hw: pointer to the HW struct 143462306a36Sopenharmony_ci * @base: pointer to the base node 143562306a36Sopenharmony_ci * @node: pointer to the node to search 143662306a36Sopenharmony_ci * 143762306a36Sopenharmony_ci * This function checks whether a given node is part of the base node 143862306a36Sopenharmony_ci * subtree or not 143962306a36Sopenharmony_ci */ 144062306a36Sopenharmony_cistatic bool 144162306a36Sopenharmony_ciice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base, 144262306a36Sopenharmony_ci struct ice_sched_node *node) 144362306a36Sopenharmony_ci{ 144462306a36Sopenharmony_ci u8 i; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci for (i = 0; i < base->num_children; i++) { 144762306a36Sopenharmony_ci struct ice_sched_node *child = base->children[i]; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (node == child) 145062306a36Sopenharmony_ci return true; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci if (child->tx_sched_layer > node->tx_sched_layer) 145362306a36Sopenharmony_ci return false; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci /* this recursion is intentional, and wouldn't 145662306a36Sopenharmony_ci * go more than 8 calls 145762306a36Sopenharmony_ci */ 145862306a36Sopenharmony_ci if (ice_sched_find_node_in_subtree(hw, child, node)) 145962306a36Sopenharmony_ci return true; 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci return false; 146262306a36Sopenharmony_ci} 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci/** 146562306a36Sopenharmony_ci * ice_sched_get_free_qgrp - Scan all queue group siblings and find a free node 146662306a36Sopenharmony_ci * @pi: port information structure 146762306a36Sopenharmony_ci * @vsi_node: software VSI handle 146862306a36Sopenharmony_ci * @qgrp_node: first queue group node identified for scanning 146962306a36Sopenharmony_ci * @owner: LAN or RDMA 147062306a36Sopenharmony_ci * 147162306a36Sopenharmony_ci * This function retrieves a free LAN or RDMA queue group node by scanning 147262306a36Sopenharmony_ci * qgrp_node and its siblings for the queue group with the fewest number 147362306a36Sopenharmony_ci * of queues currently assigned. 147462306a36Sopenharmony_ci */ 147562306a36Sopenharmony_cistatic struct ice_sched_node * 147662306a36Sopenharmony_ciice_sched_get_free_qgrp(struct ice_port_info *pi, 147762306a36Sopenharmony_ci struct ice_sched_node *vsi_node, 147862306a36Sopenharmony_ci struct ice_sched_node *qgrp_node, u8 owner) 147962306a36Sopenharmony_ci{ 148062306a36Sopenharmony_ci struct ice_sched_node *min_qgrp; 148162306a36Sopenharmony_ci u8 min_children; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci if (!qgrp_node) 148462306a36Sopenharmony_ci return qgrp_node; 148562306a36Sopenharmony_ci min_children = qgrp_node->num_children; 148662306a36Sopenharmony_ci if (!min_children) 148762306a36Sopenharmony_ci return qgrp_node; 148862306a36Sopenharmony_ci min_qgrp = qgrp_node; 148962306a36Sopenharmony_ci /* scan all queue groups until find a node which has less than the 149062306a36Sopenharmony_ci * minimum number of children. This way all queue group nodes get 149162306a36Sopenharmony_ci * equal number of shares and active. The bandwidth will be equally 149262306a36Sopenharmony_ci * distributed across all queues. 149362306a36Sopenharmony_ci */ 149462306a36Sopenharmony_ci while (qgrp_node) { 149562306a36Sopenharmony_ci /* make sure the qgroup node is part of the VSI subtree */ 149662306a36Sopenharmony_ci if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node)) 149762306a36Sopenharmony_ci if (qgrp_node->num_children < min_children && 149862306a36Sopenharmony_ci qgrp_node->owner == owner) { 149962306a36Sopenharmony_ci /* replace the new min queue group node */ 150062306a36Sopenharmony_ci min_qgrp = qgrp_node; 150162306a36Sopenharmony_ci min_children = min_qgrp->num_children; 150262306a36Sopenharmony_ci /* break if it has no children, */ 150362306a36Sopenharmony_ci if (!min_children) 150462306a36Sopenharmony_ci break; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci qgrp_node = qgrp_node->sibling; 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci return min_qgrp; 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci/** 151262306a36Sopenharmony_ci * ice_sched_get_free_qparent - Get a free LAN or RDMA queue group node 151362306a36Sopenharmony_ci * @pi: port information structure 151462306a36Sopenharmony_ci * @vsi_handle: software VSI handle 151562306a36Sopenharmony_ci * @tc: branch number 151662306a36Sopenharmony_ci * @owner: LAN or RDMA 151762306a36Sopenharmony_ci * 151862306a36Sopenharmony_ci * This function retrieves a free LAN or RDMA queue group node 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_cistruct ice_sched_node * 152162306a36Sopenharmony_ciice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 152262306a36Sopenharmony_ci u8 owner) 152362306a36Sopenharmony_ci{ 152462306a36Sopenharmony_ci struct ice_sched_node *vsi_node, *qgrp_node; 152562306a36Sopenharmony_ci struct ice_vsi_ctx *vsi_ctx; 152662306a36Sopenharmony_ci u16 max_children; 152762306a36Sopenharmony_ci u8 qgrp_layer; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci qgrp_layer = ice_sched_get_qgrp_layer(pi->hw); 153062306a36Sopenharmony_ci max_children = pi->hw->max_children[qgrp_layer]; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 153362306a36Sopenharmony_ci if (!vsi_ctx) 153462306a36Sopenharmony_ci return NULL; 153562306a36Sopenharmony_ci vsi_node = vsi_ctx->sched.vsi_node[tc]; 153662306a36Sopenharmony_ci /* validate invalid VSI ID */ 153762306a36Sopenharmony_ci if (!vsi_node) 153862306a36Sopenharmony_ci return NULL; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci /* get the first queue group node from VSI sub-tree */ 154162306a36Sopenharmony_ci qgrp_node = ice_sched_get_first_node(pi, vsi_node, qgrp_layer); 154262306a36Sopenharmony_ci while (qgrp_node) { 154362306a36Sopenharmony_ci /* make sure the qgroup node is part of the VSI subtree */ 154462306a36Sopenharmony_ci if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node)) 154562306a36Sopenharmony_ci if (qgrp_node->num_children < max_children && 154662306a36Sopenharmony_ci qgrp_node->owner == owner) 154762306a36Sopenharmony_ci break; 154862306a36Sopenharmony_ci qgrp_node = qgrp_node->sibling; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* Select the best queue group */ 155262306a36Sopenharmony_ci return ice_sched_get_free_qgrp(pi, vsi_node, qgrp_node, owner); 155362306a36Sopenharmony_ci} 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci/** 155662306a36Sopenharmony_ci * ice_sched_get_vsi_node - Get a VSI node based on VSI ID 155762306a36Sopenharmony_ci * @pi: pointer to the port information structure 155862306a36Sopenharmony_ci * @tc_node: pointer to the TC node 155962306a36Sopenharmony_ci * @vsi_handle: software VSI handle 156062306a36Sopenharmony_ci * 156162306a36Sopenharmony_ci * This function retrieves a VSI node for a given VSI ID from a given 156262306a36Sopenharmony_ci * TC branch 156362306a36Sopenharmony_ci */ 156462306a36Sopenharmony_cistatic struct ice_sched_node * 156562306a36Sopenharmony_ciice_sched_get_vsi_node(struct ice_port_info *pi, struct ice_sched_node *tc_node, 156662306a36Sopenharmony_ci u16 vsi_handle) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci struct ice_sched_node *node; 156962306a36Sopenharmony_ci u8 vsi_layer; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci vsi_layer = ice_sched_get_vsi_layer(pi->hw); 157262306a36Sopenharmony_ci node = ice_sched_get_first_node(pi, tc_node, vsi_layer); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci /* Check whether it already exists */ 157562306a36Sopenharmony_ci while (node) { 157662306a36Sopenharmony_ci if (node->vsi_handle == vsi_handle) 157762306a36Sopenharmony_ci return node; 157862306a36Sopenharmony_ci node = node->sibling; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci return node; 158262306a36Sopenharmony_ci} 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci/** 158562306a36Sopenharmony_ci * ice_sched_get_agg_node - Get an aggregator node based on aggregator ID 158662306a36Sopenharmony_ci * @pi: pointer to the port information structure 158762306a36Sopenharmony_ci * @tc_node: pointer to the TC node 158862306a36Sopenharmony_ci * @agg_id: aggregator ID 158962306a36Sopenharmony_ci * 159062306a36Sopenharmony_ci * This function retrieves an aggregator node for a given aggregator ID from 159162306a36Sopenharmony_ci * a given TC branch 159262306a36Sopenharmony_ci */ 159362306a36Sopenharmony_cistruct ice_sched_node * 159462306a36Sopenharmony_ciice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node, 159562306a36Sopenharmony_ci u32 agg_id) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci struct ice_sched_node *node; 159862306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 159962306a36Sopenharmony_ci u8 agg_layer; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (!hw) 160262306a36Sopenharmony_ci return NULL; 160362306a36Sopenharmony_ci agg_layer = ice_sched_get_agg_layer(hw); 160462306a36Sopenharmony_ci node = ice_sched_get_first_node(pi, tc_node, agg_layer); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* Check whether it already exists */ 160762306a36Sopenharmony_ci while (node) { 160862306a36Sopenharmony_ci if (node->agg_id == agg_id) 160962306a36Sopenharmony_ci return node; 161062306a36Sopenharmony_ci node = node->sibling; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci return node; 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci/** 161762306a36Sopenharmony_ci * ice_sched_calc_vsi_child_nodes - calculate number of VSI child nodes 161862306a36Sopenharmony_ci * @hw: pointer to the HW struct 161962306a36Sopenharmony_ci * @num_qs: number of queues 162062306a36Sopenharmony_ci * @num_nodes: num nodes array 162162306a36Sopenharmony_ci * 162262306a36Sopenharmony_ci * This function calculates the number of VSI child nodes based on the 162362306a36Sopenharmony_ci * number of queues. 162462306a36Sopenharmony_ci */ 162562306a36Sopenharmony_cistatic void 162662306a36Sopenharmony_ciice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci u16 num = num_qs; 162962306a36Sopenharmony_ci u8 i, qgl, vsil; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci qgl = ice_sched_get_qgrp_layer(hw); 163262306a36Sopenharmony_ci vsil = ice_sched_get_vsi_layer(hw); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci /* calculate num nodes from queue group to VSI layer */ 163562306a36Sopenharmony_ci for (i = qgl; i > vsil; i--) { 163662306a36Sopenharmony_ci /* round to the next integer if there is a remainder */ 163762306a36Sopenharmony_ci num = DIV_ROUND_UP(num, hw->max_children[i]); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci /* need at least one node */ 164062306a36Sopenharmony_ci num_nodes[i] = num ? num : 1; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci} 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci/** 164562306a36Sopenharmony_ci * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree 164662306a36Sopenharmony_ci * @pi: port information structure 164762306a36Sopenharmony_ci * @vsi_handle: software VSI handle 164862306a36Sopenharmony_ci * @tc_node: pointer to the TC node 164962306a36Sopenharmony_ci * @num_nodes: pointer to the num nodes that needs to be added per layer 165062306a36Sopenharmony_ci * @owner: node owner (LAN or RDMA) 165162306a36Sopenharmony_ci * 165262306a36Sopenharmony_ci * This function adds the VSI child nodes to tree. It gets called for 165362306a36Sopenharmony_ci * LAN and RDMA separately. 165462306a36Sopenharmony_ci */ 165562306a36Sopenharmony_cistatic int 165662306a36Sopenharmony_ciice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle, 165762306a36Sopenharmony_ci struct ice_sched_node *tc_node, u16 *num_nodes, 165862306a36Sopenharmony_ci u8 owner) 165962306a36Sopenharmony_ci{ 166062306a36Sopenharmony_ci struct ice_sched_node *parent, *node; 166162306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 166262306a36Sopenharmony_ci u32 first_node_teid; 166362306a36Sopenharmony_ci u16 num_added = 0; 166462306a36Sopenharmony_ci u8 i, qgl, vsil; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci qgl = ice_sched_get_qgrp_layer(hw); 166762306a36Sopenharmony_ci vsil = ice_sched_get_vsi_layer(hw); 166862306a36Sopenharmony_ci parent = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 166962306a36Sopenharmony_ci for (i = vsil + 1; i <= qgl; i++) { 167062306a36Sopenharmony_ci int status; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci if (!parent) 167362306a36Sopenharmony_ci return -EIO; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i, 167662306a36Sopenharmony_ci num_nodes[i], 167762306a36Sopenharmony_ci &first_node_teid, 167862306a36Sopenharmony_ci &num_added); 167962306a36Sopenharmony_ci if (status || num_nodes[i] != num_added) 168062306a36Sopenharmony_ci return -EIO; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci /* The newly added node can be a new parent for the next 168362306a36Sopenharmony_ci * layer nodes 168462306a36Sopenharmony_ci */ 168562306a36Sopenharmony_ci if (num_added) { 168662306a36Sopenharmony_ci parent = ice_sched_find_node_by_teid(tc_node, 168762306a36Sopenharmony_ci first_node_teid); 168862306a36Sopenharmony_ci node = parent; 168962306a36Sopenharmony_ci while (node) { 169062306a36Sopenharmony_ci node->owner = owner; 169162306a36Sopenharmony_ci node = node->sibling; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci } else { 169462306a36Sopenharmony_ci parent = parent->children[0]; 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci return 0; 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci/** 170262306a36Sopenharmony_ci * ice_sched_calc_vsi_support_nodes - calculate number of VSI support nodes 170362306a36Sopenharmony_ci * @pi: pointer to the port info structure 170462306a36Sopenharmony_ci * @tc_node: pointer to TC node 170562306a36Sopenharmony_ci * @num_nodes: pointer to num nodes array 170662306a36Sopenharmony_ci * 170762306a36Sopenharmony_ci * This function calculates the number of supported nodes needed to add this 170862306a36Sopenharmony_ci * VSI into Tx tree including the VSI, parent and intermediate nodes in below 170962306a36Sopenharmony_ci * layers 171062306a36Sopenharmony_ci */ 171162306a36Sopenharmony_cistatic void 171262306a36Sopenharmony_ciice_sched_calc_vsi_support_nodes(struct ice_port_info *pi, 171362306a36Sopenharmony_ci struct ice_sched_node *tc_node, u16 *num_nodes) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci struct ice_sched_node *node; 171662306a36Sopenharmony_ci u8 vsil; 171762306a36Sopenharmony_ci int i; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci vsil = ice_sched_get_vsi_layer(pi->hw); 172062306a36Sopenharmony_ci for (i = vsil; i >= pi->hw->sw_entry_point_layer; i--) 172162306a36Sopenharmony_ci /* Add intermediate nodes if TC has no children and 172262306a36Sopenharmony_ci * need at least one node for VSI 172362306a36Sopenharmony_ci */ 172462306a36Sopenharmony_ci if (!tc_node->num_children || i == vsil) { 172562306a36Sopenharmony_ci num_nodes[i]++; 172662306a36Sopenharmony_ci } else { 172762306a36Sopenharmony_ci /* If intermediate nodes are reached max children 172862306a36Sopenharmony_ci * then add a new one. 172962306a36Sopenharmony_ci */ 173062306a36Sopenharmony_ci node = ice_sched_get_first_node(pi, tc_node, (u8)i); 173162306a36Sopenharmony_ci /* scan all the siblings */ 173262306a36Sopenharmony_ci while (node) { 173362306a36Sopenharmony_ci if (node->num_children < pi->hw->max_children[i]) 173462306a36Sopenharmony_ci break; 173562306a36Sopenharmony_ci node = node->sibling; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci /* tree has one intermediate node to add this new VSI. 173962306a36Sopenharmony_ci * So no need to calculate supported nodes for below 174062306a36Sopenharmony_ci * layers. 174162306a36Sopenharmony_ci */ 174262306a36Sopenharmony_ci if (node) 174362306a36Sopenharmony_ci break; 174462306a36Sopenharmony_ci /* all the nodes are full, allocate a new one */ 174562306a36Sopenharmony_ci num_nodes[i]++; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci/** 175062306a36Sopenharmony_ci * ice_sched_add_vsi_support_nodes - add VSI supported nodes into Tx tree 175162306a36Sopenharmony_ci * @pi: port information structure 175262306a36Sopenharmony_ci * @vsi_handle: software VSI handle 175362306a36Sopenharmony_ci * @tc_node: pointer to TC node 175462306a36Sopenharmony_ci * @num_nodes: pointer to num nodes array 175562306a36Sopenharmony_ci * 175662306a36Sopenharmony_ci * This function adds the VSI supported nodes into Tx tree including the 175762306a36Sopenharmony_ci * VSI, its parent and intermediate nodes in below layers 175862306a36Sopenharmony_ci */ 175962306a36Sopenharmony_cistatic int 176062306a36Sopenharmony_ciice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle, 176162306a36Sopenharmony_ci struct ice_sched_node *tc_node, u16 *num_nodes) 176262306a36Sopenharmony_ci{ 176362306a36Sopenharmony_ci struct ice_sched_node *parent = tc_node; 176462306a36Sopenharmony_ci u32 first_node_teid; 176562306a36Sopenharmony_ci u16 num_added = 0; 176662306a36Sopenharmony_ci u8 i, vsil; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci if (!pi) 176962306a36Sopenharmony_ci return -EINVAL; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci vsil = ice_sched_get_vsi_layer(pi->hw); 177262306a36Sopenharmony_ci for (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) { 177362306a36Sopenharmony_ci int status; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, 177662306a36Sopenharmony_ci i, num_nodes[i], 177762306a36Sopenharmony_ci &first_node_teid, 177862306a36Sopenharmony_ci &num_added); 177962306a36Sopenharmony_ci if (status || num_nodes[i] != num_added) 178062306a36Sopenharmony_ci return -EIO; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci /* The newly added node can be a new parent for the next 178362306a36Sopenharmony_ci * layer nodes 178462306a36Sopenharmony_ci */ 178562306a36Sopenharmony_ci if (num_added) 178662306a36Sopenharmony_ci parent = ice_sched_find_node_by_teid(tc_node, 178762306a36Sopenharmony_ci first_node_teid); 178862306a36Sopenharmony_ci else 178962306a36Sopenharmony_ci parent = parent->children[0]; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci if (!parent) 179262306a36Sopenharmony_ci return -EIO; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci if (i == vsil) 179562306a36Sopenharmony_ci parent->vsi_handle = vsi_handle; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci return 0; 179962306a36Sopenharmony_ci} 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci/** 180262306a36Sopenharmony_ci * ice_sched_add_vsi_to_topo - add a new VSI into tree 180362306a36Sopenharmony_ci * @pi: port information structure 180462306a36Sopenharmony_ci * @vsi_handle: software VSI handle 180562306a36Sopenharmony_ci * @tc: TC number 180662306a36Sopenharmony_ci * 180762306a36Sopenharmony_ci * This function adds a new VSI into scheduler tree 180862306a36Sopenharmony_ci */ 180962306a36Sopenharmony_cistatic int 181062306a36Sopenharmony_ciice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc) 181162306a36Sopenharmony_ci{ 181262306a36Sopenharmony_ci u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; 181362306a36Sopenharmony_ci struct ice_sched_node *tc_node; 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci tc_node = ice_sched_get_tc_node(pi, tc); 181662306a36Sopenharmony_ci if (!tc_node) 181762306a36Sopenharmony_ci return -EINVAL; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci /* calculate number of supported nodes needed for this VSI */ 182062306a36Sopenharmony_ci ice_sched_calc_vsi_support_nodes(pi, tc_node, num_nodes); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci /* add VSI supported nodes to TC subtree */ 182362306a36Sopenharmony_ci return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node, 182462306a36Sopenharmony_ci num_nodes); 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci/** 182862306a36Sopenharmony_ci * ice_sched_update_vsi_child_nodes - update VSI child nodes 182962306a36Sopenharmony_ci * @pi: port information structure 183062306a36Sopenharmony_ci * @vsi_handle: software VSI handle 183162306a36Sopenharmony_ci * @tc: TC number 183262306a36Sopenharmony_ci * @new_numqs: new number of max queues 183362306a36Sopenharmony_ci * @owner: owner of this subtree 183462306a36Sopenharmony_ci * 183562306a36Sopenharmony_ci * This function updates the VSI child nodes based on the number of queues 183662306a36Sopenharmony_ci */ 183762306a36Sopenharmony_cistatic int 183862306a36Sopenharmony_ciice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle, 183962306a36Sopenharmony_ci u8 tc, u16 new_numqs, u8 owner) 184062306a36Sopenharmony_ci{ 184162306a36Sopenharmony_ci u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; 184262306a36Sopenharmony_ci struct ice_sched_node *vsi_node; 184362306a36Sopenharmony_ci struct ice_sched_node *tc_node; 184462306a36Sopenharmony_ci struct ice_vsi_ctx *vsi_ctx; 184562306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 184662306a36Sopenharmony_ci u16 prev_numqs; 184762306a36Sopenharmony_ci int status = 0; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci tc_node = ice_sched_get_tc_node(pi, tc); 185062306a36Sopenharmony_ci if (!tc_node) 185162306a36Sopenharmony_ci return -EIO; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 185462306a36Sopenharmony_ci if (!vsi_node) 185562306a36Sopenharmony_ci return -EIO; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 185862306a36Sopenharmony_ci if (!vsi_ctx) 185962306a36Sopenharmony_ci return -EINVAL; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci if (owner == ICE_SCHED_NODE_OWNER_LAN) 186262306a36Sopenharmony_ci prev_numqs = vsi_ctx->sched.max_lanq[tc]; 186362306a36Sopenharmony_ci else 186462306a36Sopenharmony_ci prev_numqs = vsi_ctx->sched.max_rdmaq[tc]; 186562306a36Sopenharmony_ci /* num queues are not changed or less than the previous number */ 186662306a36Sopenharmony_ci if (new_numqs <= prev_numqs) 186762306a36Sopenharmony_ci return status; 186862306a36Sopenharmony_ci if (owner == ICE_SCHED_NODE_OWNER_LAN) { 186962306a36Sopenharmony_ci status = ice_alloc_lan_q_ctx(hw, vsi_handle, tc, new_numqs); 187062306a36Sopenharmony_ci if (status) 187162306a36Sopenharmony_ci return status; 187262306a36Sopenharmony_ci } else { 187362306a36Sopenharmony_ci status = ice_alloc_rdma_q_ctx(hw, vsi_handle, tc, new_numqs); 187462306a36Sopenharmony_ci if (status) 187562306a36Sopenharmony_ci return status; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (new_numqs) 187962306a36Sopenharmony_ci ice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes); 188062306a36Sopenharmony_ci /* Keep the max number of queue configuration all the time. Update the 188162306a36Sopenharmony_ci * tree only if number of queues > previous number of queues. This may 188262306a36Sopenharmony_ci * leave some extra nodes in the tree if number of queues < previous 188362306a36Sopenharmony_ci * number but that wouldn't harm anything. Removing those extra nodes 188462306a36Sopenharmony_ci * may complicate the code if those nodes are part of SRL or 188562306a36Sopenharmony_ci * individually rate limited. 188662306a36Sopenharmony_ci */ 188762306a36Sopenharmony_ci status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node, 188862306a36Sopenharmony_ci new_num_nodes, owner); 188962306a36Sopenharmony_ci if (status) 189062306a36Sopenharmony_ci return status; 189162306a36Sopenharmony_ci if (owner == ICE_SCHED_NODE_OWNER_LAN) 189262306a36Sopenharmony_ci vsi_ctx->sched.max_lanq[tc] = new_numqs; 189362306a36Sopenharmony_ci else 189462306a36Sopenharmony_ci vsi_ctx->sched.max_rdmaq[tc] = new_numqs; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci return 0; 189762306a36Sopenharmony_ci} 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci/** 190062306a36Sopenharmony_ci * ice_sched_cfg_vsi - configure the new/existing VSI 190162306a36Sopenharmony_ci * @pi: port information structure 190262306a36Sopenharmony_ci * @vsi_handle: software VSI handle 190362306a36Sopenharmony_ci * @tc: TC number 190462306a36Sopenharmony_ci * @maxqs: max number of queues 190562306a36Sopenharmony_ci * @owner: LAN or RDMA 190662306a36Sopenharmony_ci * @enable: TC enabled or disabled 190762306a36Sopenharmony_ci * 190862306a36Sopenharmony_ci * This function adds/updates VSI nodes based on the number of queues. If TC is 190962306a36Sopenharmony_ci * enabled and VSI is in suspended state then resume the VSI back. If TC is 191062306a36Sopenharmony_ci * disabled then suspend the VSI if it is not already. 191162306a36Sopenharmony_ci */ 191262306a36Sopenharmony_ciint 191362306a36Sopenharmony_ciice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs, 191462306a36Sopenharmony_ci u8 owner, bool enable) 191562306a36Sopenharmony_ci{ 191662306a36Sopenharmony_ci struct ice_sched_node *vsi_node, *tc_node; 191762306a36Sopenharmony_ci struct ice_vsi_ctx *vsi_ctx; 191862306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 191962306a36Sopenharmony_ci int status = 0; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci ice_debug(pi->hw, ICE_DBG_SCHED, "add/config VSI %d\n", vsi_handle); 192262306a36Sopenharmony_ci tc_node = ice_sched_get_tc_node(pi, tc); 192362306a36Sopenharmony_ci if (!tc_node) 192462306a36Sopenharmony_ci return -EINVAL; 192562306a36Sopenharmony_ci vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 192662306a36Sopenharmony_ci if (!vsi_ctx) 192762306a36Sopenharmony_ci return -EINVAL; 192862306a36Sopenharmony_ci vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci /* suspend the VSI if TC is not enabled */ 193162306a36Sopenharmony_ci if (!enable) { 193262306a36Sopenharmony_ci if (vsi_node && vsi_node->in_use) { 193362306a36Sopenharmony_ci u32 teid = le32_to_cpu(vsi_node->info.node_teid); 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci status = ice_sched_suspend_resume_elems(hw, 1, &teid, 193662306a36Sopenharmony_ci true); 193762306a36Sopenharmony_ci if (!status) 193862306a36Sopenharmony_ci vsi_node->in_use = false; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci return status; 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci /* TC is enabled, if it is a new VSI then add it to the tree */ 194462306a36Sopenharmony_ci if (!vsi_node) { 194562306a36Sopenharmony_ci status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc); 194662306a36Sopenharmony_ci if (status) 194762306a36Sopenharmony_ci return status; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 195062306a36Sopenharmony_ci if (!vsi_node) 195162306a36Sopenharmony_ci return -EIO; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci vsi_ctx->sched.vsi_node[tc] = vsi_node; 195462306a36Sopenharmony_ci vsi_node->in_use = true; 195562306a36Sopenharmony_ci /* invalidate the max queues whenever VSI gets added first time 195662306a36Sopenharmony_ci * into the scheduler tree (boot or after reset). We need to 195762306a36Sopenharmony_ci * recreate the child nodes all the time in these cases. 195862306a36Sopenharmony_ci */ 195962306a36Sopenharmony_ci vsi_ctx->sched.max_lanq[tc] = 0; 196062306a36Sopenharmony_ci vsi_ctx->sched.max_rdmaq[tc] = 0; 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci /* update the VSI child nodes */ 196462306a36Sopenharmony_ci status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs, 196562306a36Sopenharmony_ci owner); 196662306a36Sopenharmony_ci if (status) 196762306a36Sopenharmony_ci return status; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci /* TC is enabled, resume the VSI if it is in the suspend state */ 197062306a36Sopenharmony_ci if (!vsi_node->in_use) { 197162306a36Sopenharmony_ci u32 teid = le32_to_cpu(vsi_node->info.node_teid); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci status = ice_sched_suspend_resume_elems(hw, 1, &teid, false); 197462306a36Sopenharmony_ci if (!status) 197562306a36Sopenharmony_ci vsi_node->in_use = true; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci return status; 197962306a36Sopenharmony_ci} 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci/** 198262306a36Sopenharmony_ci * ice_sched_rm_agg_vsi_info - remove aggregator related VSI info entry 198362306a36Sopenharmony_ci * @pi: port information structure 198462306a36Sopenharmony_ci * @vsi_handle: software VSI handle 198562306a36Sopenharmony_ci * 198662306a36Sopenharmony_ci * This function removes single aggregator VSI info entry from 198762306a36Sopenharmony_ci * aggregator list. 198862306a36Sopenharmony_ci */ 198962306a36Sopenharmony_cistatic void ice_sched_rm_agg_vsi_info(struct ice_port_info *pi, u16 vsi_handle) 199062306a36Sopenharmony_ci{ 199162306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 199262306a36Sopenharmony_ci struct ice_sched_agg_info *atmp; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci list_for_each_entry_safe(agg_info, atmp, &pi->hw->agg_list, 199562306a36Sopenharmony_ci list_entry) { 199662306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info; 199762306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *vtmp; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci list_for_each_entry_safe(agg_vsi_info, vtmp, 200062306a36Sopenharmony_ci &agg_info->agg_vsi_list, list_entry) 200162306a36Sopenharmony_ci if (agg_vsi_info->vsi_handle == vsi_handle) { 200262306a36Sopenharmony_ci list_del(&agg_vsi_info->list_entry); 200362306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(pi->hw), 200462306a36Sopenharmony_ci agg_vsi_info); 200562306a36Sopenharmony_ci return; 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci} 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci/** 201162306a36Sopenharmony_ci * ice_sched_is_leaf_node_present - check for a leaf node in the sub-tree 201262306a36Sopenharmony_ci * @node: pointer to the sub-tree node 201362306a36Sopenharmony_ci * 201462306a36Sopenharmony_ci * This function checks for a leaf node presence in a given sub-tree node. 201562306a36Sopenharmony_ci */ 201662306a36Sopenharmony_cistatic bool ice_sched_is_leaf_node_present(struct ice_sched_node *node) 201762306a36Sopenharmony_ci{ 201862306a36Sopenharmony_ci u8 i; 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci for (i = 0; i < node->num_children; i++) 202162306a36Sopenharmony_ci if (ice_sched_is_leaf_node_present(node->children[i])) 202262306a36Sopenharmony_ci return true; 202362306a36Sopenharmony_ci /* check for a leaf node */ 202462306a36Sopenharmony_ci return (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF); 202562306a36Sopenharmony_ci} 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci/** 202862306a36Sopenharmony_ci * ice_sched_rm_vsi_cfg - remove the VSI and its children nodes 202962306a36Sopenharmony_ci * @pi: port information structure 203062306a36Sopenharmony_ci * @vsi_handle: software VSI handle 203162306a36Sopenharmony_ci * @owner: LAN or RDMA 203262306a36Sopenharmony_ci * 203362306a36Sopenharmony_ci * This function removes the VSI and its LAN or RDMA children nodes from the 203462306a36Sopenharmony_ci * scheduler tree. 203562306a36Sopenharmony_ci */ 203662306a36Sopenharmony_cistatic int 203762306a36Sopenharmony_ciice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner) 203862306a36Sopenharmony_ci{ 203962306a36Sopenharmony_ci struct ice_vsi_ctx *vsi_ctx; 204062306a36Sopenharmony_ci int status = -EINVAL; 204162306a36Sopenharmony_ci u8 i; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci ice_debug(pi->hw, ICE_DBG_SCHED, "removing VSI %d\n", vsi_handle); 204462306a36Sopenharmony_ci if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 204562306a36Sopenharmony_ci return status; 204662306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 204762306a36Sopenharmony_ci vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 204862306a36Sopenharmony_ci if (!vsi_ctx) 204962306a36Sopenharmony_ci goto exit_sched_rm_vsi_cfg; 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci ice_for_each_traffic_class(i) { 205262306a36Sopenharmony_ci struct ice_sched_node *vsi_node, *tc_node; 205362306a36Sopenharmony_ci u8 j = 0; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci tc_node = ice_sched_get_tc_node(pi, i); 205662306a36Sopenharmony_ci if (!tc_node) 205762306a36Sopenharmony_ci continue; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 206062306a36Sopenharmony_ci if (!vsi_node) 206162306a36Sopenharmony_ci continue; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci if (ice_sched_is_leaf_node_present(vsi_node)) { 206462306a36Sopenharmony_ci ice_debug(pi->hw, ICE_DBG_SCHED, "VSI has leaf nodes in TC %d\n", i); 206562306a36Sopenharmony_ci status = -EBUSY; 206662306a36Sopenharmony_ci goto exit_sched_rm_vsi_cfg; 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci while (j < vsi_node->num_children) { 206962306a36Sopenharmony_ci if (vsi_node->children[j]->owner == owner) { 207062306a36Sopenharmony_ci ice_free_sched_node(pi, vsi_node->children[j]); 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci /* reset the counter again since the num 207362306a36Sopenharmony_ci * children will be updated after node removal 207462306a36Sopenharmony_ci */ 207562306a36Sopenharmony_ci j = 0; 207662306a36Sopenharmony_ci } else { 207762306a36Sopenharmony_ci j++; 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci } 208062306a36Sopenharmony_ci /* remove the VSI if it has no children */ 208162306a36Sopenharmony_ci if (!vsi_node->num_children) { 208262306a36Sopenharmony_ci ice_free_sched_node(pi, vsi_node); 208362306a36Sopenharmony_ci vsi_ctx->sched.vsi_node[i] = NULL; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci /* clean up aggregator related VSI info if any */ 208662306a36Sopenharmony_ci ice_sched_rm_agg_vsi_info(pi, vsi_handle); 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci if (owner == ICE_SCHED_NODE_OWNER_LAN) 208962306a36Sopenharmony_ci vsi_ctx->sched.max_lanq[i] = 0; 209062306a36Sopenharmony_ci else 209162306a36Sopenharmony_ci vsi_ctx->sched.max_rdmaq[i] = 0; 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci status = 0; 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ciexit_sched_rm_vsi_cfg: 209662306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 209762306a36Sopenharmony_ci return status; 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci/** 210162306a36Sopenharmony_ci * ice_rm_vsi_lan_cfg - remove VSI and its LAN children nodes 210262306a36Sopenharmony_ci * @pi: port information structure 210362306a36Sopenharmony_ci * @vsi_handle: software VSI handle 210462306a36Sopenharmony_ci * 210562306a36Sopenharmony_ci * This function clears the VSI and its LAN children nodes from scheduler tree 210662306a36Sopenharmony_ci * for all TCs. 210762306a36Sopenharmony_ci */ 210862306a36Sopenharmony_ciint ice_rm_vsi_lan_cfg(struct ice_port_info *pi, u16 vsi_handle) 210962306a36Sopenharmony_ci{ 211062306a36Sopenharmony_ci return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_LAN); 211162306a36Sopenharmony_ci} 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci/** 211462306a36Sopenharmony_ci * ice_rm_vsi_rdma_cfg - remove VSI and its RDMA children nodes 211562306a36Sopenharmony_ci * @pi: port information structure 211662306a36Sopenharmony_ci * @vsi_handle: software VSI handle 211762306a36Sopenharmony_ci * 211862306a36Sopenharmony_ci * This function clears the VSI and its RDMA children nodes from scheduler tree 211962306a36Sopenharmony_ci * for all TCs. 212062306a36Sopenharmony_ci */ 212162306a36Sopenharmony_ciint ice_rm_vsi_rdma_cfg(struct ice_port_info *pi, u16 vsi_handle) 212262306a36Sopenharmony_ci{ 212362306a36Sopenharmony_ci return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_RDMA); 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci/** 212762306a36Sopenharmony_ci * ice_get_agg_info - get the aggregator ID 212862306a36Sopenharmony_ci * @hw: pointer to the hardware structure 212962306a36Sopenharmony_ci * @agg_id: aggregator ID 213062306a36Sopenharmony_ci * 213162306a36Sopenharmony_ci * This function validates aggregator ID. The function returns info if 213262306a36Sopenharmony_ci * aggregator ID is present in list otherwise it returns null. 213362306a36Sopenharmony_ci */ 213462306a36Sopenharmony_cistatic struct ice_sched_agg_info * 213562306a36Sopenharmony_ciice_get_agg_info(struct ice_hw *hw, u32 agg_id) 213662306a36Sopenharmony_ci{ 213762306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci list_for_each_entry(agg_info, &hw->agg_list, list_entry) 214062306a36Sopenharmony_ci if (agg_info->agg_id == agg_id) 214162306a36Sopenharmony_ci return agg_info; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci return NULL; 214462306a36Sopenharmony_ci} 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci/** 214762306a36Sopenharmony_ci * ice_sched_get_free_vsi_parent - Find a free parent node in aggregator subtree 214862306a36Sopenharmony_ci * @hw: pointer to the HW struct 214962306a36Sopenharmony_ci * @node: pointer to a child node 215062306a36Sopenharmony_ci * @num_nodes: num nodes count array 215162306a36Sopenharmony_ci * 215262306a36Sopenharmony_ci * This function walks through the aggregator subtree to find a free parent 215362306a36Sopenharmony_ci * node 215462306a36Sopenharmony_ci */ 215562306a36Sopenharmony_cistruct ice_sched_node * 215662306a36Sopenharmony_ciice_sched_get_free_vsi_parent(struct ice_hw *hw, struct ice_sched_node *node, 215762306a36Sopenharmony_ci u16 *num_nodes) 215862306a36Sopenharmony_ci{ 215962306a36Sopenharmony_ci u8 l = node->tx_sched_layer; 216062306a36Sopenharmony_ci u8 vsil, i; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci vsil = ice_sched_get_vsi_layer(hw); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci /* Is it VSI parent layer ? */ 216562306a36Sopenharmony_ci if (l == vsil - 1) 216662306a36Sopenharmony_ci return (node->num_children < hw->max_children[l]) ? node : NULL; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci /* We have intermediate nodes. Let's walk through the subtree. If the 216962306a36Sopenharmony_ci * intermediate node has space to add a new node then clear the count 217062306a36Sopenharmony_ci */ 217162306a36Sopenharmony_ci if (node->num_children < hw->max_children[l]) 217262306a36Sopenharmony_ci num_nodes[l] = 0; 217362306a36Sopenharmony_ci /* The below recursive call is intentional and wouldn't go more than 217462306a36Sopenharmony_ci * 2 or 3 iterations. 217562306a36Sopenharmony_ci */ 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci for (i = 0; i < node->num_children; i++) { 217862306a36Sopenharmony_ci struct ice_sched_node *parent; 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci parent = ice_sched_get_free_vsi_parent(hw, node->children[i], 218162306a36Sopenharmony_ci num_nodes); 218262306a36Sopenharmony_ci if (parent) 218362306a36Sopenharmony_ci return parent; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci return NULL; 218762306a36Sopenharmony_ci} 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci/** 219062306a36Sopenharmony_ci * ice_sched_update_parent - update the new parent in SW DB 219162306a36Sopenharmony_ci * @new_parent: pointer to a new parent node 219262306a36Sopenharmony_ci * @node: pointer to a child node 219362306a36Sopenharmony_ci * 219462306a36Sopenharmony_ci * This function removes the child from the old parent and adds it to a new 219562306a36Sopenharmony_ci * parent 219662306a36Sopenharmony_ci */ 219762306a36Sopenharmony_civoid 219862306a36Sopenharmony_ciice_sched_update_parent(struct ice_sched_node *new_parent, 219962306a36Sopenharmony_ci struct ice_sched_node *node) 220062306a36Sopenharmony_ci{ 220162306a36Sopenharmony_ci struct ice_sched_node *old_parent; 220262306a36Sopenharmony_ci u8 i, j; 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci old_parent = node->parent; 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci /* update the old parent children */ 220762306a36Sopenharmony_ci for (i = 0; i < old_parent->num_children; i++) 220862306a36Sopenharmony_ci if (old_parent->children[i] == node) { 220962306a36Sopenharmony_ci for (j = i + 1; j < old_parent->num_children; j++) 221062306a36Sopenharmony_ci old_parent->children[j - 1] = 221162306a36Sopenharmony_ci old_parent->children[j]; 221262306a36Sopenharmony_ci old_parent->num_children--; 221362306a36Sopenharmony_ci break; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci /* now move the node to a new parent */ 221762306a36Sopenharmony_ci new_parent->children[new_parent->num_children++] = node; 221862306a36Sopenharmony_ci node->parent = new_parent; 221962306a36Sopenharmony_ci node->info.parent_teid = new_parent->info.node_teid; 222062306a36Sopenharmony_ci} 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci/** 222362306a36Sopenharmony_ci * ice_sched_move_nodes - move child nodes to a given parent 222462306a36Sopenharmony_ci * @pi: port information structure 222562306a36Sopenharmony_ci * @parent: pointer to parent node 222662306a36Sopenharmony_ci * @num_items: number of child nodes to be moved 222762306a36Sopenharmony_ci * @list: pointer to child node teids 222862306a36Sopenharmony_ci * 222962306a36Sopenharmony_ci * This function move the child nodes to a given parent. 223062306a36Sopenharmony_ci */ 223162306a36Sopenharmony_ciint 223262306a36Sopenharmony_ciice_sched_move_nodes(struct ice_port_info *pi, struct ice_sched_node *parent, 223362306a36Sopenharmony_ci u16 num_items, u32 *list) 223462306a36Sopenharmony_ci{ 223562306a36Sopenharmony_ci struct ice_aqc_move_elem *buf; 223662306a36Sopenharmony_ci struct ice_sched_node *node; 223762306a36Sopenharmony_ci u16 i, grps_movd = 0; 223862306a36Sopenharmony_ci struct ice_hw *hw; 223962306a36Sopenharmony_ci int status = 0; 224062306a36Sopenharmony_ci u16 buf_len; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci hw = pi->hw; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci if (!parent || !num_items) 224562306a36Sopenharmony_ci return -EINVAL; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci /* Does parent have enough space */ 224862306a36Sopenharmony_ci if (parent->num_children + num_items > 224962306a36Sopenharmony_ci hw->max_children[parent->tx_sched_layer]) 225062306a36Sopenharmony_ci return -ENOSPC; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci buf_len = struct_size(buf, teid, 1); 225362306a36Sopenharmony_ci buf = kzalloc(buf_len, GFP_KERNEL); 225462306a36Sopenharmony_ci if (!buf) 225562306a36Sopenharmony_ci return -ENOMEM; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci for (i = 0; i < num_items; i++) { 225862306a36Sopenharmony_ci node = ice_sched_find_node_by_teid(pi->root, list[i]); 225962306a36Sopenharmony_ci if (!node) { 226062306a36Sopenharmony_ci status = -EINVAL; 226162306a36Sopenharmony_ci goto move_err_exit; 226262306a36Sopenharmony_ci } 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci buf->hdr.src_parent_teid = node->info.parent_teid; 226562306a36Sopenharmony_ci buf->hdr.dest_parent_teid = parent->info.node_teid; 226662306a36Sopenharmony_ci buf->teid[0] = node->info.node_teid; 226762306a36Sopenharmony_ci buf->hdr.num_elems = cpu_to_le16(1); 226862306a36Sopenharmony_ci status = ice_aq_move_sched_elems(hw, 1, buf, buf_len, 226962306a36Sopenharmony_ci &grps_movd, NULL); 227062306a36Sopenharmony_ci if (status && grps_movd != 1) { 227162306a36Sopenharmony_ci status = -EIO; 227262306a36Sopenharmony_ci goto move_err_exit; 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci /* update the SW DB */ 227662306a36Sopenharmony_ci ice_sched_update_parent(parent, node); 227762306a36Sopenharmony_ci } 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_cimove_err_exit: 228062306a36Sopenharmony_ci kfree(buf); 228162306a36Sopenharmony_ci return status; 228262306a36Sopenharmony_ci} 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci/** 228562306a36Sopenharmony_ci * ice_sched_move_vsi_to_agg - move VSI to aggregator node 228662306a36Sopenharmony_ci * @pi: port information structure 228762306a36Sopenharmony_ci * @vsi_handle: software VSI handle 228862306a36Sopenharmony_ci * @agg_id: aggregator ID 228962306a36Sopenharmony_ci * @tc: TC number 229062306a36Sopenharmony_ci * 229162306a36Sopenharmony_ci * This function moves a VSI to an aggregator node or its subtree. 229262306a36Sopenharmony_ci * Intermediate nodes may be created if required. 229362306a36Sopenharmony_ci */ 229462306a36Sopenharmony_cistatic int 229562306a36Sopenharmony_ciice_sched_move_vsi_to_agg(struct ice_port_info *pi, u16 vsi_handle, u32 agg_id, 229662306a36Sopenharmony_ci u8 tc) 229762306a36Sopenharmony_ci{ 229862306a36Sopenharmony_ci struct ice_sched_node *vsi_node, *agg_node, *tc_node, *parent; 229962306a36Sopenharmony_ci u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; 230062306a36Sopenharmony_ci u32 first_node_teid, vsi_teid; 230162306a36Sopenharmony_ci u16 num_nodes_added; 230262306a36Sopenharmony_ci u8 aggl, vsil, i; 230362306a36Sopenharmony_ci int status; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci tc_node = ice_sched_get_tc_node(pi, tc); 230662306a36Sopenharmony_ci if (!tc_node) 230762306a36Sopenharmony_ci return -EIO; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 231062306a36Sopenharmony_ci if (!agg_node) 231162306a36Sopenharmony_ci return -ENOENT; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 231462306a36Sopenharmony_ci if (!vsi_node) 231562306a36Sopenharmony_ci return -ENOENT; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci /* Is this VSI already part of given aggregator? */ 231862306a36Sopenharmony_ci if (ice_sched_find_node_in_subtree(pi->hw, agg_node, vsi_node)) 231962306a36Sopenharmony_ci return 0; 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci aggl = ice_sched_get_agg_layer(pi->hw); 232262306a36Sopenharmony_ci vsil = ice_sched_get_vsi_layer(pi->hw); 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci /* set intermediate node count to 1 between aggregator and VSI layers */ 232562306a36Sopenharmony_ci for (i = aggl + 1; i < vsil; i++) 232662306a36Sopenharmony_ci num_nodes[i] = 1; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci /* Check if the aggregator subtree has any free node to add the VSI */ 232962306a36Sopenharmony_ci for (i = 0; i < agg_node->num_children; i++) { 233062306a36Sopenharmony_ci parent = ice_sched_get_free_vsi_parent(pi->hw, 233162306a36Sopenharmony_ci agg_node->children[i], 233262306a36Sopenharmony_ci num_nodes); 233362306a36Sopenharmony_ci if (parent) 233462306a36Sopenharmony_ci goto move_nodes; 233562306a36Sopenharmony_ci } 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci /* add new nodes */ 233862306a36Sopenharmony_ci parent = agg_node; 233962306a36Sopenharmony_ci for (i = aggl + 1; i < vsil; i++) { 234062306a36Sopenharmony_ci status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i, 234162306a36Sopenharmony_ci num_nodes[i], 234262306a36Sopenharmony_ci &first_node_teid, 234362306a36Sopenharmony_ci &num_nodes_added); 234462306a36Sopenharmony_ci if (status || num_nodes[i] != num_nodes_added) 234562306a36Sopenharmony_ci return -EIO; 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci /* The newly added node can be a new parent for the next 234862306a36Sopenharmony_ci * layer nodes 234962306a36Sopenharmony_ci */ 235062306a36Sopenharmony_ci if (num_nodes_added) 235162306a36Sopenharmony_ci parent = ice_sched_find_node_by_teid(tc_node, 235262306a36Sopenharmony_ci first_node_teid); 235362306a36Sopenharmony_ci else 235462306a36Sopenharmony_ci parent = parent->children[0]; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci if (!parent) 235762306a36Sopenharmony_ci return -EIO; 235862306a36Sopenharmony_ci } 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_cimove_nodes: 236162306a36Sopenharmony_ci vsi_teid = le32_to_cpu(vsi_node->info.node_teid); 236262306a36Sopenharmony_ci return ice_sched_move_nodes(pi, parent, 1, &vsi_teid); 236362306a36Sopenharmony_ci} 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci/** 236662306a36Sopenharmony_ci * ice_move_all_vsi_to_dflt_agg - move all VSI(s) to default aggregator 236762306a36Sopenharmony_ci * @pi: port information structure 236862306a36Sopenharmony_ci * @agg_info: aggregator info 236962306a36Sopenharmony_ci * @tc: traffic class number 237062306a36Sopenharmony_ci * @rm_vsi_info: true or false 237162306a36Sopenharmony_ci * 237262306a36Sopenharmony_ci * This function move all the VSI(s) to the default aggregator and delete 237362306a36Sopenharmony_ci * aggregator VSI info based on passed in boolean parameter rm_vsi_info. The 237462306a36Sopenharmony_ci * caller holds the scheduler lock. 237562306a36Sopenharmony_ci */ 237662306a36Sopenharmony_cistatic int 237762306a36Sopenharmony_ciice_move_all_vsi_to_dflt_agg(struct ice_port_info *pi, 237862306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info, u8 tc, 237962306a36Sopenharmony_ci bool rm_vsi_info) 238062306a36Sopenharmony_ci{ 238162306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info; 238262306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *tmp; 238362306a36Sopenharmony_ci int status = 0; 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci list_for_each_entry_safe(agg_vsi_info, tmp, &agg_info->agg_vsi_list, 238662306a36Sopenharmony_ci list_entry) { 238762306a36Sopenharmony_ci u16 vsi_handle = agg_vsi_info->vsi_handle; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci /* Move VSI to default aggregator */ 239062306a36Sopenharmony_ci if (!ice_is_tc_ena(agg_vsi_info->tc_bitmap[0], tc)) 239162306a36Sopenharmony_ci continue; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci status = ice_sched_move_vsi_to_agg(pi, vsi_handle, 239462306a36Sopenharmony_ci ICE_DFLT_AGG_ID, tc); 239562306a36Sopenharmony_ci if (status) 239662306a36Sopenharmony_ci break; 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci clear_bit(tc, agg_vsi_info->tc_bitmap); 239962306a36Sopenharmony_ci if (rm_vsi_info && !agg_vsi_info->tc_bitmap[0]) { 240062306a36Sopenharmony_ci list_del(&agg_vsi_info->list_entry); 240162306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(pi->hw), agg_vsi_info); 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci } 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci return status; 240662306a36Sopenharmony_ci} 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci/** 240962306a36Sopenharmony_ci * ice_sched_is_agg_inuse - check whether the aggregator is in use or not 241062306a36Sopenharmony_ci * @pi: port information structure 241162306a36Sopenharmony_ci * @node: node pointer 241262306a36Sopenharmony_ci * 241362306a36Sopenharmony_ci * This function checks whether the aggregator is attached with any VSI or not. 241462306a36Sopenharmony_ci */ 241562306a36Sopenharmony_cistatic bool 241662306a36Sopenharmony_ciice_sched_is_agg_inuse(struct ice_port_info *pi, struct ice_sched_node *node) 241762306a36Sopenharmony_ci{ 241862306a36Sopenharmony_ci u8 vsil, i; 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci vsil = ice_sched_get_vsi_layer(pi->hw); 242162306a36Sopenharmony_ci if (node->tx_sched_layer < vsil - 1) { 242262306a36Sopenharmony_ci for (i = 0; i < node->num_children; i++) 242362306a36Sopenharmony_ci if (ice_sched_is_agg_inuse(pi, node->children[i])) 242462306a36Sopenharmony_ci return true; 242562306a36Sopenharmony_ci return false; 242662306a36Sopenharmony_ci } else { 242762306a36Sopenharmony_ci return node->num_children ? true : false; 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci} 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci/** 243262306a36Sopenharmony_ci * ice_sched_rm_agg_cfg - remove the aggregator node 243362306a36Sopenharmony_ci * @pi: port information structure 243462306a36Sopenharmony_ci * @agg_id: aggregator ID 243562306a36Sopenharmony_ci * @tc: TC number 243662306a36Sopenharmony_ci * 243762306a36Sopenharmony_ci * This function removes the aggregator node and intermediate nodes if any 243862306a36Sopenharmony_ci * from the given TC 243962306a36Sopenharmony_ci */ 244062306a36Sopenharmony_cistatic int 244162306a36Sopenharmony_ciice_sched_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc) 244262306a36Sopenharmony_ci{ 244362306a36Sopenharmony_ci struct ice_sched_node *tc_node, *agg_node; 244462306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci tc_node = ice_sched_get_tc_node(pi, tc); 244762306a36Sopenharmony_ci if (!tc_node) 244862306a36Sopenharmony_ci return -EIO; 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 245162306a36Sopenharmony_ci if (!agg_node) 245262306a36Sopenharmony_ci return -ENOENT; 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci /* Can't remove the aggregator node if it has children */ 245562306a36Sopenharmony_ci if (ice_sched_is_agg_inuse(pi, agg_node)) 245662306a36Sopenharmony_ci return -EBUSY; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci /* need to remove the whole subtree if aggregator node is the 245962306a36Sopenharmony_ci * only child. 246062306a36Sopenharmony_ci */ 246162306a36Sopenharmony_ci while (agg_node->tx_sched_layer > hw->sw_entry_point_layer) { 246262306a36Sopenharmony_ci struct ice_sched_node *parent = agg_node->parent; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci if (!parent) 246562306a36Sopenharmony_ci return -EIO; 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci if (parent->num_children > 1) 246862306a36Sopenharmony_ci break; 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci agg_node = parent; 247162306a36Sopenharmony_ci } 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci ice_free_sched_node(pi, agg_node); 247462306a36Sopenharmony_ci return 0; 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci/** 247862306a36Sopenharmony_ci * ice_rm_agg_cfg_tc - remove aggregator configuration for TC 247962306a36Sopenharmony_ci * @pi: port information structure 248062306a36Sopenharmony_ci * @agg_info: aggregator ID 248162306a36Sopenharmony_ci * @tc: TC number 248262306a36Sopenharmony_ci * @rm_vsi_info: bool value true or false 248362306a36Sopenharmony_ci * 248462306a36Sopenharmony_ci * This function removes aggregator reference to VSI of given TC. It removes 248562306a36Sopenharmony_ci * the aggregator configuration completely for requested TC. The caller needs 248662306a36Sopenharmony_ci * to hold the scheduler lock. 248762306a36Sopenharmony_ci */ 248862306a36Sopenharmony_cistatic int 248962306a36Sopenharmony_ciice_rm_agg_cfg_tc(struct ice_port_info *pi, struct ice_sched_agg_info *agg_info, 249062306a36Sopenharmony_ci u8 tc, bool rm_vsi_info) 249162306a36Sopenharmony_ci{ 249262306a36Sopenharmony_ci int status = 0; 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci /* If nothing to remove - return success */ 249562306a36Sopenharmony_ci if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc)) 249662306a36Sopenharmony_ci goto exit_rm_agg_cfg_tc; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci status = ice_move_all_vsi_to_dflt_agg(pi, agg_info, tc, rm_vsi_info); 249962306a36Sopenharmony_ci if (status) 250062306a36Sopenharmony_ci goto exit_rm_agg_cfg_tc; 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci /* Delete aggregator node(s) */ 250362306a36Sopenharmony_ci status = ice_sched_rm_agg_cfg(pi, agg_info->agg_id, tc); 250462306a36Sopenharmony_ci if (status) 250562306a36Sopenharmony_ci goto exit_rm_agg_cfg_tc; 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci clear_bit(tc, agg_info->tc_bitmap); 250862306a36Sopenharmony_ciexit_rm_agg_cfg_tc: 250962306a36Sopenharmony_ci return status; 251062306a36Sopenharmony_ci} 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci/** 251362306a36Sopenharmony_ci * ice_save_agg_tc_bitmap - save aggregator TC bitmap 251462306a36Sopenharmony_ci * @pi: port information structure 251562306a36Sopenharmony_ci * @agg_id: aggregator ID 251662306a36Sopenharmony_ci * @tc_bitmap: 8 bits TC bitmap 251762306a36Sopenharmony_ci * 251862306a36Sopenharmony_ci * Save aggregator TC bitmap. This function needs to be called with scheduler 251962306a36Sopenharmony_ci * lock held. 252062306a36Sopenharmony_ci */ 252162306a36Sopenharmony_cistatic int 252262306a36Sopenharmony_ciice_save_agg_tc_bitmap(struct ice_port_info *pi, u32 agg_id, 252362306a36Sopenharmony_ci unsigned long *tc_bitmap) 252462306a36Sopenharmony_ci{ 252562306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci agg_info = ice_get_agg_info(pi->hw, agg_id); 252862306a36Sopenharmony_ci if (!agg_info) 252962306a36Sopenharmony_ci return -EINVAL; 253062306a36Sopenharmony_ci bitmap_copy(agg_info->replay_tc_bitmap, tc_bitmap, 253162306a36Sopenharmony_ci ICE_MAX_TRAFFIC_CLASS); 253262306a36Sopenharmony_ci return 0; 253362306a36Sopenharmony_ci} 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci/** 253662306a36Sopenharmony_ci * ice_sched_add_agg_cfg - create an aggregator node 253762306a36Sopenharmony_ci * @pi: port information structure 253862306a36Sopenharmony_ci * @agg_id: aggregator ID 253962306a36Sopenharmony_ci * @tc: TC number 254062306a36Sopenharmony_ci * 254162306a36Sopenharmony_ci * This function creates an aggregator node and intermediate nodes if required 254262306a36Sopenharmony_ci * for the given TC 254362306a36Sopenharmony_ci */ 254462306a36Sopenharmony_cistatic int 254562306a36Sopenharmony_ciice_sched_add_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc) 254662306a36Sopenharmony_ci{ 254762306a36Sopenharmony_ci struct ice_sched_node *parent, *agg_node, *tc_node; 254862306a36Sopenharmony_ci u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; 254962306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 255062306a36Sopenharmony_ci u32 first_node_teid; 255162306a36Sopenharmony_ci u16 num_nodes_added; 255262306a36Sopenharmony_ci int status = 0; 255362306a36Sopenharmony_ci u8 i, aggl; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci tc_node = ice_sched_get_tc_node(pi, tc); 255662306a36Sopenharmony_ci if (!tc_node) 255762306a36Sopenharmony_ci return -EIO; 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 256062306a36Sopenharmony_ci /* Does Agg node already exist ? */ 256162306a36Sopenharmony_ci if (agg_node) 256262306a36Sopenharmony_ci return status; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci aggl = ice_sched_get_agg_layer(hw); 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci /* need one node in Agg layer */ 256762306a36Sopenharmony_ci num_nodes[aggl] = 1; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci /* Check whether the intermediate nodes have space to add the 257062306a36Sopenharmony_ci * new aggregator. If they are full, then SW needs to allocate a new 257162306a36Sopenharmony_ci * intermediate node on those layers 257262306a36Sopenharmony_ci */ 257362306a36Sopenharmony_ci for (i = hw->sw_entry_point_layer; i < aggl; i++) { 257462306a36Sopenharmony_ci parent = ice_sched_get_first_node(pi, tc_node, i); 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci /* scan all the siblings */ 257762306a36Sopenharmony_ci while (parent) { 257862306a36Sopenharmony_ci if (parent->num_children < hw->max_children[i]) 257962306a36Sopenharmony_ci break; 258062306a36Sopenharmony_ci parent = parent->sibling; 258162306a36Sopenharmony_ci } 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci /* all the nodes are full, reserve one for this layer */ 258462306a36Sopenharmony_ci if (!parent) 258562306a36Sopenharmony_ci num_nodes[i]++; 258662306a36Sopenharmony_ci } 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci /* add the aggregator node */ 258962306a36Sopenharmony_ci parent = tc_node; 259062306a36Sopenharmony_ci for (i = hw->sw_entry_point_layer; i <= aggl; i++) { 259162306a36Sopenharmony_ci if (!parent) 259262306a36Sopenharmony_ci return -EIO; 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i, 259562306a36Sopenharmony_ci num_nodes[i], 259662306a36Sopenharmony_ci &first_node_teid, 259762306a36Sopenharmony_ci &num_nodes_added); 259862306a36Sopenharmony_ci if (status || num_nodes[i] != num_nodes_added) 259962306a36Sopenharmony_ci return -EIO; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci /* The newly added node can be a new parent for the next 260262306a36Sopenharmony_ci * layer nodes 260362306a36Sopenharmony_ci */ 260462306a36Sopenharmony_ci if (num_nodes_added) { 260562306a36Sopenharmony_ci parent = ice_sched_find_node_by_teid(tc_node, 260662306a36Sopenharmony_ci first_node_teid); 260762306a36Sopenharmony_ci /* register aggregator ID with the aggregator node */ 260862306a36Sopenharmony_ci if (parent && i == aggl) 260962306a36Sopenharmony_ci parent->agg_id = agg_id; 261062306a36Sopenharmony_ci } else { 261162306a36Sopenharmony_ci parent = parent->children[0]; 261262306a36Sopenharmony_ci } 261362306a36Sopenharmony_ci } 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci return 0; 261662306a36Sopenharmony_ci} 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci/** 261962306a36Sopenharmony_ci * ice_sched_cfg_agg - configure aggregator node 262062306a36Sopenharmony_ci * @pi: port information structure 262162306a36Sopenharmony_ci * @agg_id: aggregator ID 262262306a36Sopenharmony_ci * @agg_type: aggregator type queue, VSI, or aggregator group 262362306a36Sopenharmony_ci * @tc_bitmap: bits TC bitmap 262462306a36Sopenharmony_ci * 262562306a36Sopenharmony_ci * It registers a unique aggregator node into scheduler services. It 262662306a36Sopenharmony_ci * allows a user to register with a unique ID to track it's resources. 262762306a36Sopenharmony_ci * The aggregator type determines if this is a queue group, VSI group 262862306a36Sopenharmony_ci * or aggregator group. It then creates the aggregator node(s) for requested 262962306a36Sopenharmony_ci * TC(s) or removes an existing aggregator node including its configuration 263062306a36Sopenharmony_ci * if indicated via tc_bitmap. Call ice_rm_agg_cfg to release aggregator 263162306a36Sopenharmony_ci * resources and remove aggregator ID. 263262306a36Sopenharmony_ci * This function needs to be called with scheduler lock held. 263362306a36Sopenharmony_ci */ 263462306a36Sopenharmony_cistatic int 263562306a36Sopenharmony_ciice_sched_cfg_agg(struct ice_port_info *pi, u32 agg_id, 263662306a36Sopenharmony_ci enum ice_agg_type agg_type, unsigned long *tc_bitmap) 263762306a36Sopenharmony_ci{ 263862306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 263962306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 264062306a36Sopenharmony_ci int status = 0; 264162306a36Sopenharmony_ci u8 tc; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci agg_info = ice_get_agg_info(hw, agg_id); 264462306a36Sopenharmony_ci if (!agg_info) { 264562306a36Sopenharmony_ci /* Create new entry for new aggregator ID */ 264662306a36Sopenharmony_ci agg_info = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*agg_info), 264762306a36Sopenharmony_ci GFP_KERNEL); 264862306a36Sopenharmony_ci if (!agg_info) 264962306a36Sopenharmony_ci return -ENOMEM; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci agg_info->agg_id = agg_id; 265262306a36Sopenharmony_ci agg_info->agg_type = agg_type; 265362306a36Sopenharmony_ci agg_info->tc_bitmap[0] = 0; 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci /* Initialize the aggregator VSI list head */ 265662306a36Sopenharmony_ci INIT_LIST_HEAD(&agg_info->agg_vsi_list); 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci /* Add new entry in aggregator list */ 265962306a36Sopenharmony_ci list_add(&agg_info->list_entry, &hw->agg_list); 266062306a36Sopenharmony_ci } 266162306a36Sopenharmony_ci /* Create aggregator node(s) for requested TC(s) */ 266262306a36Sopenharmony_ci ice_for_each_traffic_class(tc) { 266362306a36Sopenharmony_ci if (!ice_is_tc_ena(*tc_bitmap, tc)) { 266462306a36Sopenharmony_ci /* Delete aggregator cfg TC if it exists previously */ 266562306a36Sopenharmony_ci status = ice_rm_agg_cfg_tc(pi, agg_info, tc, false); 266662306a36Sopenharmony_ci if (status) 266762306a36Sopenharmony_ci break; 266862306a36Sopenharmony_ci continue; 266962306a36Sopenharmony_ci } 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci /* Check if aggregator node for TC already exists */ 267262306a36Sopenharmony_ci if (ice_is_tc_ena(agg_info->tc_bitmap[0], tc)) 267362306a36Sopenharmony_ci continue; 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci /* Create new aggregator node for TC */ 267662306a36Sopenharmony_ci status = ice_sched_add_agg_cfg(pi, agg_id, tc); 267762306a36Sopenharmony_ci if (status) 267862306a36Sopenharmony_ci break; 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci /* Save aggregator node's TC information */ 268162306a36Sopenharmony_ci set_bit(tc, agg_info->tc_bitmap); 268262306a36Sopenharmony_ci } 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci return status; 268562306a36Sopenharmony_ci} 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci/** 268862306a36Sopenharmony_ci * ice_cfg_agg - config aggregator node 268962306a36Sopenharmony_ci * @pi: port information structure 269062306a36Sopenharmony_ci * @agg_id: aggregator ID 269162306a36Sopenharmony_ci * @agg_type: aggregator type queue, VSI, or aggregator group 269262306a36Sopenharmony_ci * @tc_bitmap: bits TC bitmap 269362306a36Sopenharmony_ci * 269462306a36Sopenharmony_ci * This function configures aggregator node(s). 269562306a36Sopenharmony_ci */ 269662306a36Sopenharmony_ciint 269762306a36Sopenharmony_ciice_cfg_agg(struct ice_port_info *pi, u32 agg_id, enum ice_agg_type agg_type, 269862306a36Sopenharmony_ci u8 tc_bitmap) 269962306a36Sopenharmony_ci{ 270062306a36Sopenharmony_ci unsigned long bitmap = tc_bitmap; 270162306a36Sopenharmony_ci int status; 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 270462306a36Sopenharmony_ci status = ice_sched_cfg_agg(pi, agg_id, agg_type, &bitmap); 270562306a36Sopenharmony_ci if (!status) 270662306a36Sopenharmony_ci status = ice_save_agg_tc_bitmap(pi, agg_id, &bitmap); 270762306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 270862306a36Sopenharmony_ci return status; 270962306a36Sopenharmony_ci} 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci/** 271262306a36Sopenharmony_ci * ice_get_agg_vsi_info - get the aggregator ID 271362306a36Sopenharmony_ci * @agg_info: aggregator info 271462306a36Sopenharmony_ci * @vsi_handle: software VSI handle 271562306a36Sopenharmony_ci * 271662306a36Sopenharmony_ci * The function returns aggregator VSI info based on VSI handle. This function 271762306a36Sopenharmony_ci * needs to be called with scheduler lock held. 271862306a36Sopenharmony_ci */ 271962306a36Sopenharmony_cistatic struct ice_sched_agg_vsi_info * 272062306a36Sopenharmony_ciice_get_agg_vsi_info(struct ice_sched_agg_info *agg_info, u16 vsi_handle) 272162306a36Sopenharmony_ci{ 272262306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci list_for_each_entry(agg_vsi_info, &agg_info->agg_vsi_list, list_entry) 272562306a36Sopenharmony_ci if (agg_vsi_info->vsi_handle == vsi_handle) 272662306a36Sopenharmony_ci return agg_vsi_info; 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci return NULL; 272962306a36Sopenharmony_ci} 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci/** 273262306a36Sopenharmony_ci * ice_get_vsi_agg_info - get the aggregator info of VSI 273362306a36Sopenharmony_ci * @hw: pointer to the hardware structure 273462306a36Sopenharmony_ci * @vsi_handle: Sw VSI handle 273562306a36Sopenharmony_ci * 273662306a36Sopenharmony_ci * The function returns aggregator info of VSI represented via vsi_handle. The 273762306a36Sopenharmony_ci * VSI has in this case a different aggregator than the default one. This 273862306a36Sopenharmony_ci * function needs to be called with scheduler lock held. 273962306a36Sopenharmony_ci */ 274062306a36Sopenharmony_cistatic struct ice_sched_agg_info * 274162306a36Sopenharmony_ciice_get_vsi_agg_info(struct ice_hw *hw, u16 vsi_handle) 274262306a36Sopenharmony_ci{ 274362306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci list_for_each_entry(agg_info, &hw->agg_list, list_entry) { 274662306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info; 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle); 274962306a36Sopenharmony_ci if (agg_vsi_info) 275062306a36Sopenharmony_ci return agg_info; 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci return NULL; 275362306a36Sopenharmony_ci} 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci/** 275662306a36Sopenharmony_ci * ice_save_agg_vsi_tc_bitmap - save aggregator VSI TC bitmap 275762306a36Sopenharmony_ci * @pi: port information structure 275862306a36Sopenharmony_ci * @agg_id: aggregator ID 275962306a36Sopenharmony_ci * @vsi_handle: software VSI handle 276062306a36Sopenharmony_ci * @tc_bitmap: TC bitmap of enabled TC(s) 276162306a36Sopenharmony_ci * 276262306a36Sopenharmony_ci * Save VSI to aggregator TC bitmap. This function needs to call with scheduler 276362306a36Sopenharmony_ci * lock held. 276462306a36Sopenharmony_ci */ 276562306a36Sopenharmony_cistatic int 276662306a36Sopenharmony_ciice_save_agg_vsi_tc_bitmap(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle, 276762306a36Sopenharmony_ci unsigned long *tc_bitmap) 276862306a36Sopenharmony_ci{ 276962306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info; 277062306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci agg_info = ice_get_agg_info(pi->hw, agg_id); 277362306a36Sopenharmony_ci if (!agg_info) 277462306a36Sopenharmony_ci return -EINVAL; 277562306a36Sopenharmony_ci /* check if entry already exist */ 277662306a36Sopenharmony_ci agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle); 277762306a36Sopenharmony_ci if (!agg_vsi_info) 277862306a36Sopenharmony_ci return -EINVAL; 277962306a36Sopenharmony_ci bitmap_copy(agg_vsi_info->replay_tc_bitmap, tc_bitmap, 278062306a36Sopenharmony_ci ICE_MAX_TRAFFIC_CLASS); 278162306a36Sopenharmony_ci return 0; 278262306a36Sopenharmony_ci} 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci/** 278562306a36Sopenharmony_ci * ice_sched_assoc_vsi_to_agg - associate/move VSI to new/default aggregator 278662306a36Sopenharmony_ci * @pi: port information structure 278762306a36Sopenharmony_ci * @agg_id: aggregator ID 278862306a36Sopenharmony_ci * @vsi_handle: software VSI handle 278962306a36Sopenharmony_ci * @tc_bitmap: TC bitmap of enabled TC(s) 279062306a36Sopenharmony_ci * 279162306a36Sopenharmony_ci * This function moves VSI to a new or default aggregator node. If VSI is 279262306a36Sopenharmony_ci * already associated to the aggregator node then no operation is performed on 279362306a36Sopenharmony_ci * the tree. This function needs to be called with scheduler lock held. 279462306a36Sopenharmony_ci */ 279562306a36Sopenharmony_cistatic int 279662306a36Sopenharmony_ciice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, 279762306a36Sopenharmony_ci u16 vsi_handle, unsigned long *tc_bitmap) 279862306a36Sopenharmony_ci{ 279962306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info, *iter, *old_agg_vsi_info = NULL; 280062306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info, *old_agg_info; 280162306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 280262306a36Sopenharmony_ci int status = 0; 280362306a36Sopenharmony_ci u8 tc; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 280662306a36Sopenharmony_ci return -EINVAL; 280762306a36Sopenharmony_ci agg_info = ice_get_agg_info(hw, agg_id); 280862306a36Sopenharmony_ci if (!agg_info) 280962306a36Sopenharmony_ci return -EINVAL; 281062306a36Sopenharmony_ci /* If the VSI is already part of another aggregator then update 281162306a36Sopenharmony_ci * its VSI info list 281262306a36Sopenharmony_ci */ 281362306a36Sopenharmony_ci old_agg_info = ice_get_vsi_agg_info(hw, vsi_handle); 281462306a36Sopenharmony_ci if (old_agg_info && old_agg_info != agg_info) { 281562306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *vtmp; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci list_for_each_entry_safe(iter, vtmp, 281862306a36Sopenharmony_ci &old_agg_info->agg_vsi_list, 281962306a36Sopenharmony_ci list_entry) 282062306a36Sopenharmony_ci if (iter->vsi_handle == vsi_handle) { 282162306a36Sopenharmony_ci old_agg_vsi_info = iter; 282262306a36Sopenharmony_ci break; 282362306a36Sopenharmony_ci } 282462306a36Sopenharmony_ci } 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci /* check if entry already exist */ 282762306a36Sopenharmony_ci agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle); 282862306a36Sopenharmony_ci if (!agg_vsi_info) { 282962306a36Sopenharmony_ci /* Create new entry for VSI under aggregator list */ 283062306a36Sopenharmony_ci agg_vsi_info = devm_kzalloc(ice_hw_to_dev(hw), 283162306a36Sopenharmony_ci sizeof(*agg_vsi_info), GFP_KERNEL); 283262306a36Sopenharmony_ci if (!agg_vsi_info) 283362306a36Sopenharmony_ci return -EINVAL; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci /* add VSI ID into the aggregator list */ 283662306a36Sopenharmony_ci agg_vsi_info->vsi_handle = vsi_handle; 283762306a36Sopenharmony_ci list_add(&agg_vsi_info->list_entry, &agg_info->agg_vsi_list); 283862306a36Sopenharmony_ci } 283962306a36Sopenharmony_ci /* Move VSI node to new aggregator node for requested TC(s) */ 284062306a36Sopenharmony_ci ice_for_each_traffic_class(tc) { 284162306a36Sopenharmony_ci if (!ice_is_tc_ena(*tc_bitmap, tc)) 284262306a36Sopenharmony_ci continue; 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci /* Move VSI to new aggregator */ 284562306a36Sopenharmony_ci status = ice_sched_move_vsi_to_agg(pi, vsi_handle, agg_id, tc); 284662306a36Sopenharmony_ci if (status) 284762306a36Sopenharmony_ci break; 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ci set_bit(tc, agg_vsi_info->tc_bitmap); 285062306a36Sopenharmony_ci if (old_agg_vsi_info) 285162306a36Sopenharmony_ci clear_bit(tc, old_agg_vsi_info->tc_bitmap); 285262306a36Sopenharmony_ci } 285362306a36Sopenharmony_ci if (old_agg_vsi_info && !old_agg_vsi_info->tc_bitmap[0]) { 285462306a36Sopenharmony_ci list_del(&old_agg_vsi_info->list_entry); 285562306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(pi->hw), old_agg_vsi_info); 285662306a36Sopenharmony_ci } 285762306a36Sopenharmony_ci return status; 285862306a36Sopenharmony_ci} 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci/** 286162306a36Sopenharmony_ci * ice_sched_rm_unused_rl_prof - remove unused RL profile 286262306a36Sopenharmony_ci * @pi: port information structure 286362306a36Sopenharmony_ci * 286462306a36Sopenharmony_ci * This function removes unused rate limit profiles from the HW and 286562306a36Sopenharmony_ci * SW DB. The caller needs to hold scheduler lock. 286662306a36Sopenharmony_ci */ 286762306a36Sopenharmony_cistatic void ice_sched_rm_unused_rl_prof(struct ice_port_info *pi) 286862306a36Sopenharmony_ci{ 286962306a36Sopenharmony_ci u16 ln; 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci for (ln = 0; ln < pi->hw->num_tx_sched_layers; ln++) { 287262306a36Sopenharmony_ci struct ice_aqc_rl_profile_info *rl_prof_elem; 287362306a36Sopenharmony_ci struct ice_aqc_rl_profile_info *rl_prof_tmp; 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ci list_for_each_entry_safe(rl_prof_elem, rl_prof_tmp, 287662306a36Sopenharmony_ci &pi->rl_prof_list[ln], list_entry) { 287762306a36Sopenharmony_ci if (!ice_sched_del_rl_profile(pi->hw, rl_prof_elem)) 287862306a36Sopenharmony_ci ice_debug(pi->hw, ICE_DBG_SCHED, "Removed rl profile\n"); 287962306a36Sopenharmony_ci } 288062306a36Sopenharmony_ci } 288162306a36Sopenharmony_ci} 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci/** 288462306a36Sopenharmony_ci * ice_sched_update_elem - update element 288562306a36Sopenharmony_ci * @hw: pointer to the HW struct 288662306a36Sopenharmony_ci * @node: pointer to node 288762306a36Sopenharmony_ci * @info: node info to update 288862306a36Sopenharmony_ci * 288962306a36Sopenharmony_ci * Update the HW DB, and local SW DB of node. Update the scheduling 289062306a36Sopenharmony_ci * parameters of node from argument info data buffer (Info->data buf) and 289162306a36Sopenharmony_ci * returns success or error on config sched element failure. The caller 289262306a36Sopenharmony_ci * needs to hold scheduler lock. 289362306a36Sopenharmony_ci */ 289462306a36Sopenharmony_cistatic int 289562306a36Sopenharmony_ciice_sched_update_elem(struct ice_hw *hw, struct ice_sched_node *node, 289662306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data *info) 289762306a36Sopenharmony_ci{ 289862306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data buf; 289962306a36Sopenharmony_ci u16 elem_cfgd = 0; 290062306a36Sopenharmony_ci u16 num_elems = 1; 290162306a36Sopenharmony_ci int status; 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci buf = *info; 290462306a36Sopenharmony_ci /* Parent TEID is reserved field in this aq call */ 290562306a36Sopenharmony_ci buf.parent_teid = 0; 290662306a36Sopenharmony_ci /* Element type is reserved field in this aq call */ 290762306a36Sopenharmony_ci buf.data.elem_type = 0; 290862306a36Sopenharmony_ci /* Flags is reserved field in this aq call */ 290962306a36Sopenharmony_ci buf.data.flags = 0; 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci /* Update HW DB */ 291262306a36Sopenharmony_ci /* Configure element node */ 291362306a36Sopenharmony_ci status = ice_aq_cfg_sched_elems(hw, num_elems, &buf, sizeof(buf), 291462306a36Sopenharmony_ci &elem_cfgd, NULL); 291562306a36Sopenharmony_ci if (status || elem_cfgd != num_elems) { 291662306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_SCHED, "Config sched elem error\n"); 291762306a36Sopenharmony_ci return -EIO; 291862306a36Sopenharmony_ci } 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci /* Config success case */ 292162306a36Sopenharmony_ci /* Now update local SW DB */ 292262306a36Sopenharmony_ci /* Only copy the data portion of info buffer */ 292362306a36Sopenharmony_ci node->info.data = info->data; 292462306a36Sopenharmony_ci return status; 292562306a36Sopenharmony_ci} 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci/** 292862306a36Sopenharmony_ci * ice_sched_cfg_node_bw_alloc - configure node BW weight/alloc params 292962306a36Sopenharmony_ci * @hw: pointer to the HW struct 293062306a36Sopenharmony_ci * @node: sched node to configure 293162306a36Sopenharmony_ci * @rl_type: rate limit type CIR, EIR, or shared 293262306a36Sopenharmony_ci * @bw_alloc: BW weight/allocation 293362306a36Sopenharmony_ci * 293462306a36Sopenharmony_ci * This function configures node element's BW allocation. 293562306a36Sopenharmony_ci */ 293662306a36Sopenharmony_cistatic int 293762306a36Sopenharmony_ciice_sched_cfg_node_bw_alloc(struct ice_hw *hw, struct ice_sched_node *node, 293862306a36Sopenharmony_ci enum ice_rl_type rl_type, u16 bw_alloc) 293962306a36Sopenharmony_ci{ 294062306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data buf; 294162306a36Sopenharmony_ci struct ice_aqc_txsched_elem *data; 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci buf = node->info; 294462306a36Sopenharmony_ci data = &buf.data; 294562306a36Sopenharmony_ci if (rl_type == ICE_MIN_BW) { 294662306a36Sopenharmony_ci data->valid_sections |= ICE_AQC_ELEM_VALID_CIR; 294762306a36Sopenharmony_ci data->cir_bw.bw_alloc = cpu_to_le16(bw_alloc); 294862306a36Sopenharmony_ci } else if (rl_type == ICE_MAX_BW) { 294962306a36Sopenharmony_ci data->valid_sections |= ICE_AQC_ELEM_VALID_EIR; 295062306a36Sopenharmony_ci data->eir_bw.bw_alloc = cpu_to_le16(bw_alloc); 295162306a36Sopenharmony_ci } else { 295262306a36Sopenharmony_ci return -EINVAL; 295362306a36Sopenharmony_ci } 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci /* Configure element */ 295662306a36Sopenharmony_ci return ice_sched_update_elem(hw, node, &buf); 295762306a36Sopenharmony_ci} 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci/** 296062306a36Sopenharmony_ci * ice_move_vsi_to_agg - moves VSI to new or default aggregator 296162306a36Sopenharmony_ci * @pi: port information structure 296262306a36Sopenharmony_ci * @agg_id: aggregator ID 296362306a36Sopenharmony_ci * @vsi_handle: software VSI handle 296462306a36Sopenharmony_ci * @tc_bitmap: TC bitmap of enabled TC(s) 296562306a36Sopenharmony_ci * 296662306a36Sopenharmony_ci * Move or associate VSI to a new or default aggregator node. 296762306a36Sopenharmony_ci */ 296862306a36Sopenharmony_ciint 296962306a36Sopenharmony_ciice_move_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle, 297062306a36Sopenharmony_ci u8 tc_bitmap) 297162306a36Sopenharmony_ci{ 297262306a36Sopenharmony_ci unsigned long bitmap = tc_bitmap; 297362306a36Sopenharmony_ci int status; 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 297662306a36Sopenharmony_ci status = ice_sched_assoc_vsi_to_agg(pi, agg_id, vsi_handle, 297762306a36Sopenharmony_ci (unsigned long *)&bitmap); 297862306a36Sopenharmony_ci if (!status) 297962306a36Sopenharmony_ci status = ice_save_agg_vsi_tc_bitmap(pi, agg_id, vsi_handle, 298062306a36Sopenharmony_ci (unsigned long *)&bitmap); 298162306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 298262306a36Sopenharmony_ci return status; 298362306a36Sopenharmony_ci} 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci/** 298662306a36Sopenharmony_ci * ice_set_clear_cir_bw - set or clear CIR BW 298762306a36Sopenharmony_ci * @bw_t_info: bandwidth type information structure 298862306a36Sopenharmony_ci * @bw: bandwidth in Kbps - Kilo bits per sec 298962306a36Sopenharmony_ci * 299062306a36Sopenharmony_ci * Save or clear CIR bandwidth (BW) in the passed param bw_t_info. 299162306a36Sopenharmony_ci */ 299262306a36Sopenharmony_cistatic void ice_set_clear_cir_bw(struct ice_bw_type_info *bw_t_info, u32 bw) 299362306a36Sopenharmony_ci{ 299462306a36Sopenharmony_ci if (bw == ICE_SCHED_DFLT_BW) { 299562306a36Sopenharmony_ci clear_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap); 299662306a36Sopenharmony_ci bw_t_info->cir_bw.bw = 0; 299762306a36Sopenharmony_ci } else { 299862306a36Sopenharmony_ci /* Save type of BW information */ 299962306a36Sopenharmony_ci set_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap); 300062306a36Sopenharmony_ci bw_t_info->cir_bw.bw = bw; 300162306a36Sopenharmony_ci } 300262306a36Sopenharmony_ci} 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci/** 300562306a36Sopenharmony_ci * ice_set_clear_eir_bw - set or clear EIR BW 300662306a36Sopenharmony_ci * @bw_t_info: bandwidth type information structure 300762306a36Sopenharmony_ci * @bw: bandwidth in Kbps - Kilo bits per sec 300862306a36Sopenharmony_ci * 300962306a36Sopenharmony_ci * Save or clear EIR bandwidth (BW) in the passed param bw_t_info. 301062306a36Sopenharmony_ci */ 301162306a36Sopenharmony_cistatic void ice_set_clear_eir_bw(struct ice_bw_type_info *bw_t_info, u32 bw) 301262306a36Sopenharmony_ci{ 301362306a36Sopenharmony_ci if (bw == ICE_SCHED_DFLT_BW) { 301462306a36Sopenharmony_ci clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap); 301562306a36Sopenharmony_ci bw_t_info->eir_bw.bw = 0; 301662306a36Sopenharmony_ci } else { 301762306a36Sopenharmony_ci /* EIR BW and Shared BW profiles are mutually exclusive and 301862306a36Sopenharmony_ci * hence only one of them may be set for any given element. 301962306a36Sopenharmony_ci * First clear earlier saved shared BW information. 302062306a36Sopenharmony_ci */ 302162306a36Sopenharmony_ci clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap); 302262306a36Sopenharmony_ci bw_t_info->shared_bw = 0; 302362306a36Sopenharmony_ci /* save EIR BW information */ 302462306a36Sopenharmony_ci set_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap); 302562306a36Sopenharmony_ci bw_t_info->eir_bw.bw = bw; 302662306a36Sopenharmony_ci } 302762306a36Sopenharmony_ci} 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci/** 303062306a36Sopenharmony_ci * ice_set_clear_shared_bw - set or clear shared BW 303162306a36Sopenharmony_ci * @bw_t_info: bandwidth type information structure 303262306a36Sopenharmony_ci * @bw: bandwidth in Kbps - Kilo bits per sec 303362306a36Sopenharmony_ci * 303462306a36Sopenharmony_ci * Save or clear shared bandwidth (BW) in the passed param bw_t_info. 303562306a36Sopenharmony_ci */ 303662306a36Sopenharmony_cistatic void ice_set_clear_shared_bw(struct ice_bw_type_info *bw_t_info, u32 bw) 303762306a36Sopenharmony_ci{ 303862306a36Sopenharmony_ci if (bw == ICE_SCHED_DFLT_BW) { 303962306a36Sopenharmony_ci clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap); 304062306a36Sopenharmony_ci bw_t_info->shared_bw = 0; 304162306a36Sopenharmony_ci } else { 304262306a36Sopenharmony_ci /* EIR BW and Shared BW profiles are mutually exclusive and 304362306a36Sopenharmony_ci * hence only one of them may be set for any given element. 304462306a36Sopenharmony_ci * First clear earlier saved EIR BW information. 304562306a36Sopenharmony_ci */ 304662306a36Sopenharmony_ci clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap); 304762306a36Sopenharmony_ci bw_t_info->eir_bw.bw = 0; 304862306a36Sopenharmony_ci /* save shared BW information */ 304962306a36Sopenharmony_ci set_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap); 305062306a36Sopenharmony_ci bw_t_info->shared_bw = bw; 305162306a36Sopenharmony_ci } 305262306a36Sopenharmony_ci} 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci/** 305562306a36Sopenharmony_ci * ice_sched_save_vsi_bw - save VSI node's BW information 305662306a36Sopenharmony_ci * @pi: port information structure 305762306a36Sopenharmony_ci * @vsi_handle: sw VSI handle 305862306a36Sopenharmony_ci * @tc: traffic class 305962306a36Sopenharmony_ci * @rl_type: rate limit type min, max, or shared 306062306a36Sopenharmony_ci * @bw: bandwidth in Kbps - Kilo bits per sec 306162306a36Sopenharmony_ci * 306262306a36Sopenharmony_ci * Save BW information of VSI type node for post replay use. 306362306a36Sopenharmony_ci */ 306462306a36Sopenharmony_cistatic int 306562306a36Sopenharmony_ciice_sched_save_vsi_bw(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 306662306a36Sopenharmony_ci enum ice_rl_type rl_type, u32 bw) 306762306a36Sopenharmony_ci{ 306862306a36Sopenharmony_ci struct ice_vsi_ctx *vsi_ctx; 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 307162306a36Sopenharmony_ci return -EINVAL; 307262306a36Sopenharmony_ci vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 307362306a36Sopenharmony_ci if (!vsi_ctx) 307462306a36Sopenharmony_ci return -EINVAL; 307562306a36Sopenharmony_ci switch (rl_type) { 307662306a36Sopenharmony_ci case ICE_MIN_BW: 307762306a36Sopenharmony_ci ice_set_clear_cir_bw(&vsi_ctx->sched.bw_t_info[tc], bw); 307862306a36Sopenharmony_ci break; 307962306a36Sopenharmony_ci case ICE_MAX_BW: 308062306a36Sopenharmony_ci ice_set_clear_eir_bw(&vsi_ctx->sched.bw_t_info[tc], bw); 308162306a36Sopenharmony_ci break; 308262306a36Sopenharmony_ci case ICE_SHARED_BW: 308362306a36Sopenharmony_ci ice_set_clear_shared_bw(&vsi_ctx->sched.bw_t_info[tc], bw); 308462306a36Sopenharmony_ci break; 308562306a36Sopenharmony_ci default: 308662306a36Sopenharmony_ci return -EINVAL; 308762306a36Sopenharmony_ci } 308862306a36Sopenharmony_ci return 0; 308962306a36Sopenharmony_ci} 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci/** 309262306a36Sopenharmony_ci * ice_sched_calc_wakeup - calculate RL profile wakeup parameter 309362306a36Sopenharmony_ci * @hw: pointer to the HW struct 309462306a36Sopenharmony_ci * @bw: bandwidth in Kbps 309562306a36Sopenharmony_ci * 309662306a36Sopenharmony_ci * This function calculates the wakeup parameter of RL profile. 309762306a36Sopenharmony_ci */ 309862306a36Sopenharmony_cistatic u16 ice_sched_calc_wakeup(struct ice_hw *hw, s32 bw) 309962306a36Sopenharmony_ci{ 310062306a36Sopenharmony_ci s64 bytes_per_sec, wakeup_int, wakeup_a, wakeup_b, wakeup_f; 310162306a36Sopenharmony_ci s32 wakeup_f_int; 310262306a36Sopenharmony_ci u16 wakeup = 0; 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci /* Get the wakeup integer value */ 310562306a36Sopenharmony_ci bytes_per_sec = div64_long(((s64)bw * 1000), BITS_PER_BYTE); 310662306a36Sopenharmony_ci wakeup_int = div64_long(hw->psm_clk_freq, bytes_per_sec); 310762306a36Sopenharmony_ci if (wakeup_int > 63) { 310862306a36Sopenharmony_ci wakeup = (u16)((1 << 15) | wakeup_int); 310962306a36Sopenharmony_ci } else { 311062306a36Sopenharmony_ci /* Calculate fraction value up to 4 decimals 311162306a36Sopenharmony_ci * Convert Integer value to a constant multiplier 311262306a36Sopenharmony_ci */ 311362306a36Sopenharmony_ci wakeup_b = (s64)ICE_RL_PROF_MULTIPLIER * wakeup_int; 311462306a36Sopenharmony_ci wakeup_a = div64_long((s64)ICE_RL_PROF_MULTIPLIER * 311562306a36Sopenharmony_ci hw->psm_clk_freq, bytes_per_sec); 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci /* Get Fraction value */ 311862306a36Sopenharmony_ci wakeup_f = wakeup_a - wakeup_b; 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci /* Round up the Fractional value via Ceil(Fractional value) */ 312162306a36Sopenharmony_ci if (wakeup_f > div64_long(ICE_RL_PROF_MULTIPLIER, 2)) 312262306a36Sopenharmony_ci wakeup_f += 1; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci wakeup_f_int = (s32)div64_long(wakeup_f * ICE_RL_PROF_FRACTION, 312562306a36Sopenharmony_ci ICE_RL_PROF_MULTIPLIER); 312662306a36Sopenharmony_ci wakeup |= (u16)(wakeup_int << 9); 312762306a36Sopenharmony_ci wakeup |= (u16)(0x1ff & wakeup_f_int); 312862306a36Sopenharmony_ci } 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci return wakeup; 313162306a36Sopenharmony_ci} 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci/** 313462306a36Sopenharmony_ci * ice_sched_bw_to_rl_profile - convert BW to profile parameters 313562306a36Sopenharmony_ci * @hw: pointer to the HW struct 313662306a36Sopenharmony_ci * @bw: bandwidth in Kbps 313762306a36Sopenharmony_ci * @profile: profile parameters to return 313862306a36Sopenharmony_ci * 313962306a36Sopenharmony_ci * This function converts the BW to profile structure format. 314062306a36Sopenharmony_ci */ 314162306a36Sopenharmony_cistatic int 314262306a36Sopenharmony_ciice_sched_bw_to_rl_profile(struct ice_hw *hw, u32 bw, 314362306a36Sopenharmony_ci struct ice_aqc_rl_profile_elem *profile) 314462306a36Sopenharmony_ci{ 314562306a36Sopenharmony_ci s64 bytes_per_sec, ts_rate, mv_tmp; 314662306a36Sopenharmony_ci int status = -EINVAL; 314762306a36Sopenharmony_ci bool found = false; 314862306a36Sopenharmony_ci s32 encode = 0; 314962306a36Sopenharmony_ci s64 mv = 0; 315062306a36Sopenharmony_ci s32 i; 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci /* Bw settings range is from 0.5Mb/sec to 100Gb/sec */ 315362306a36Sopenharmony_ci if (bw < ICE_SCHED_MIN_BW || bw > ICE_SCHED_MAX_BW) 315462306a36Sopenharmony_ci return status; 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci /* Bytes per second from Kbps */ 315762306a36Sopenharmony_ci bytes_per_sec = div64_long(((s64)bw * 1000), BITS_PER_BYTE); 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci /* encode is 6 bits but really useful are 5 bits */ 316062306a36Sopenharmony_ci for (i = 0; i < 64; i++) { 316162306a36Sopenharmony_ci u64 pow_result = BIT_ULL(i); 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci ts_rate = div64_long((s64)hw->psm_clk_freq, 316462306a36Sopenharmony_ci pow_result * ICE_RL_PROF_TS_MULTIPLIER); 316562306a36Sopenharmony_ci if (ts_rate <= 0) 316662306a36Sopenharmony_ci continue; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci /* Multiplier value */ 316962306a36Sopenharmony_ci mv_tmp = div64_long(bytes_per_sec * ICE_RL_PROF_MULTIPLIER, 317062306a36Sopenharmony_ci ts_rate); 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci /* Round to the nearest ICE_RL_PROF_MULTIPLIER */ 317362306a36Sopenharmony_ci mv = round_up_64bit(mv_tmp, ICE_RL_PROF_MULTIPLIER); 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci /* First multiplier value greater than the given 317662306a36Sopenharmony_ci * accuracy bytes 317762306a36Sopenharmony_ci */ 317862306a36Sopenharmony_ci if (mv > ICE_RL_PROF_ACCURACY_BYTES) { 317962306a36Sopenharmony_ci encode = i; 318062306a36Sopenharmony_ci found = true; 318162306a36Sopenharmony_ci break; 318262306a36Sopenharmony_ci } 318362306a36Sopenharmony_ci } 318462306a36Sopenharmony_ci if (found) { 318562306a36Sopenharmony_ci u16 wm; 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci wm = ice_sched_calc_wakeup(hw, bw); 318862306a36Sopenharmony_ci profile->rl_multiply = cpu_to_le16(mv); 318962306a36Sopenharmony_ci profile->wake_up_calc = cpu_to_le16(wm); 319062306a36Sopenharmony_ci profile->rl_encode = cpu_to_le16(encode); 319162306a36Sopenharmony_ci status = 0; 319262306a36Sopenharmony_ci } else { 319362306a36Sopenharmony_ci status = -ENOENT; 319462306a36Sopenharmony_ci } 319562306a36Sopenharmony_ci 319662306a36Sopenharmony_ci return status; 319762306a36Sopenharmony_ci} 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_ci/** 320062306a36Sopenharmony_ci * ice_sched_add_rl_profile - add RL profile 320162306a36Sopenharmony_ci * @pi: port information structure 320262306a36Sopenharmony_ci * @rl_type: type of rate limit BW - min, max, or shared 320362306a36Sopenharmony_ci * @bw: bandwidth in Kbps - Kilo bits per sec 320462306a36Sopenharmony_ci * @layer_num: specifies in which layer to create profile 320562306a36Sopenharmony_ci * 320662306a36Sopenharmony_ci * This function first checks the existing list for corresponding BW 320762306a36Sopenharmony_ci * parameter. If it exists, it returns the associated profile otherwise 320862306a36Sopenharmony_ci * it creates a new rate limit profile for requested BW, and adds it to 320962306a36Sopenharmony_ci * the HW DB and local list. It returns the new profile or null on error. 321062306a36Sopenharmony_ci * The caller needs to hold the scheduler lock. 321162306a36Sopenharmony_ci */ 321262306a36Sopenharmony_cistatic struct ice_aqc_rl_profile_info * 321362306a36Sopenharmony_ciice_sched_add_rl_profile(struct ice_port_info *pi, 321462306a36Sopenharmony_ci enum ice_rl_type rl_type, u32 bw, u8 layer_num) 321562306a36Sopenharmony_ci{ 321662306a36Sopenharmony_ci struct ice_aqc_rl_profile_info *rl_prof_elem; 321762306a36Sopenharmony_ci u16 profiles_added = 0, num_profiles = 1; 321862306a36Sopenharmony_ci struct ice_aqc_rl_profile_elem *buf; 321962306a36Sopenharmony_ci struct ice_hw *hw; 322062306a36Sopenharmony_ci u8 profile_type; 322162306a36Sopenharmony_ci int status; 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci if (layer_num >= ICE_AQC_TOPO_MAX_LEVEL_NUM) 322462306a36Sopenharmony_ci return NULL; 322562306a36Sopenharmony_ci switch (rl_type) { 322662306a36Sopenharmony_ci case ICE_MIN_BW: 322762306a36Sopenharmony_ci profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR; 322862306a36Sopenharmony_ci break; 322962306a36Sopenharmony_ci case ICE_MAX_BW: 323062306a36Sopenharmony_ci profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR; 323162306a36Sopenharmony_ci break; 323262306a36Sopenharmony_ci case ICE_SHARED_BW: 323362306a36Sopenharmony_ci profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL; 323462306a36Sopenharmony_ci break; 323562306a36Sopenharmony_ci default: 323662306a36Sopenharmony_ci return NULL; 323762306a36Sopenharmony_ci } 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci if (!pi) 324062306a36Sopenharmony_ci return NULL; 324162306a36Sopenharmony_ci hw = pi->hw; 324262306a36Sopenharmony_ci list_for_each_entry(rl_prof_elem, &pi->rl_prof_list[layer_num], 324362306a36Sopenharmony_ci list_entry) 324462306a36Sopenharmony_ci if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) == 324562306a36Sopenharmony_ci profile_type && rl_prof_elem->bw == bw) 324662306a36Sopenharmony_ci /* Return existing profile ID info */ 324762306a36Sopenharmony_ci return rl_prof_elem; 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci /* Create new profile ID */ 325062306a36Sopenharmony_ci rl_prof_elem = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rl_prof_elem), 325162306a36Sopenharmony_ci GFP_KERNEL); 325262306a36Sopenharmony_ci 325362306a36Sopenharmony_ci if (!rl_prof_elem) 325462306a36Sopenharmony_ci return NULL; 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_ci status = ice_sched_bw_to_rl_profile(hw, bw, &rl_prof_elem->profile); 325762306a36Sopenharmony_ci if (status) 325862306a36Sopenharmony_ci goto exit_add_rl_prof; 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci rl_prof_elem->bw = bw; 326162306a36Sopenharmony_ci /* layer_num is zero relative, and fw expects level from 1 to 9 */ 326262306a36Sopenharmony_ci rl_prof_elem->profile.level = layer_num + 1; 326362306a36Sopenharmony_ci rl_prof_elem->profile.flags = profile_type; 326462306a36Sopenharmony_ci rl_prof_elem->profile.max_burst_size = cpu_to_le16(hw->max_burst_size); 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci /* Create new entry in HW DB */ 326762306a36Sopenharmony_ci buf = &rl_prof_elem->profile; 326862306a36Sopenharmony_ci status = ice_aq_add_rl_profile(hw, num_profiles, buf, sizeof(*buf), 326962306a36Sopenharmony_ci &profiles_added, NULL); 327062306a36Sopenharmony_ci if (status || profiles_added != num_profiles) 327162306a36Sopenharmony_ci goto exit_add_rl_prof; 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci /* Good entry - add in the list */ 327462306a36Sopenharmony_ci rl_prof_elem->prof_id_ref = 0; 327562306a36Sopenharmony_ci list_add(&rl_prof_elem->list_entry, &pi->rl_prof_list[layer_num]); 327662306a36Sopenharmony_ci return rl_prof_elem; 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ciexit_add_rl_prof: 327962306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), rl_prof_elem); 328062306a36Sopenharmony_ci return NULL; 328162306a36Sopenharmony_ci} 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci/** 328462306a36Sopenharmony_ci * ice_sched_cfg_node_bw_lmt - configure node sched params 328562306a36Sopenharmony_ci * @hw: pointer to the HW struct 328662306a36Sopenharmony_ci * @node: sched node to configure 328762306a36Sopenharmony_ci * @rl_type: rate limit type CIR, EIR, or shared 328862306a36Sopenharmony_ci * @rl_prof_id: rate limit profile ID 328962306a36Sopenharmony_ci * 329062306a36Sopenharmony_ci * This function configures node element's BW limit. 329162306a36Sopenharmony_ci */ 329262306a36Sopenharmony_cistatic int 329362306a36Sopenharmony_ciice_sched_cfg_node_bw_lmt(struct ice_hw *hw, struct ice_sched_node *node, 329462306a36Sopenharmony_ci enum ice_rl_type rl_type, u16 rl_prof_id) 329562306a36Sopenharmony_ci{ 329662306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data buf; 329762306a36Sopenharmony_ci struct ice_aqc_txsched_elem *data; 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci buf = node->info; 330062306a36Sopenharmony_ci data = &buf.data; 330162306a36Sopenharmony_ci switch (rl_type) { 330262306a36Sopenharmony_ci case ICE_MIN_BW: 330362306a36Sopenharmony_ci data->valid_sections |= ICE_AQC_ELEM_VALID_CIR; 330462306a36Sopenharmony_ci data->cir_bw.bw_profile_idx = cpu_to_le16(rl_prof_id); 330562306a36Sopenharmony_ci break; 330662306a36Sopenharmony_ci case ICE_MAX_BW: 330762306a36Sopenharmony_ci /* EIR BW and Shared BW profiles are mutually exclusive and 330862306a36Sopenharmony_ci * hence only one of them may be set for any given element 330962306a36Sopenharmony_ci */ 331062306a36Sopenharmony_ci if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED) 331162306a36Sopenharmony_ci return -EIO; 331262306a36Sopenharmony_ci data->valid_sections |= ICE_AQC_ELEM_VALID_EIR; 331362306a36Sopenharmony_ci data->eir_bw.bw_profile_idx = cpu_to_le16(rl_prof_id); 331462306a36Sopenharmony_ci break; 331562306a36Sopenharmony_ci case ICE_SHARED_BW: 331662306a36Sopenharmony_ci /* Check for removing shared BW */ 331762306a36Sopenharmony_ci if (rl_prof_id == ICE_SCHED_NO_SHARED_RL_PROF_ID) { 331862306a36Sopenharmony_ci /* remove shared profile */ 331962306a36Sopenharmony_ci data->valid_sections &= ~ICE_AQC_ELEM_VALID_SHARED; 332062306a36Sopenharmony_ci data->srl_id = 0; /* clear SRL field */ 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci /* enable back EIR to default profile */ 332362306a36Sopenharmony_ci data->valid_sections |= ICE_AQC_ELEM_VALID_EIR; 332462306a36Sopenharmony_ci data->eir_bw.bw_profile_idx = 332562306a36Sopenharmony_ci cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID); 332662306a36Sopenharmony_ci break; 332762306a36Sopenharmony_ci } 332862306a36Sopenharmony_ci /* EIR BW and Shared BW profiles are mutually exclusive and 332962306a36Sopenharmony_ci * hence only one of them may be set for any given element 333062306a36Sopenharmony_ci */ 333162306a36Sopenharmony_ci if ((data->valid_sections & ICE_AQC_ELEM_VALID_EIR) && 333262306a36Sopenharmony_ci (le16_to_cpu(data->eir_bw.bw_profile_idx) != 333362306a36Sopenharmony_ci ICE_SCHED_DFLT_RL_PROF_ID)) 333462306a36Sopenharmony_ci return -EIO; 333562306a36Sopenharmony_ci /* EIR BW is set to default, disable it */ 333662306a36Sopenharmony_ci data->valid_sections &= ~ICE_AQC_ELEM_VALID_EIR; 333762306a36Sopenharmony_ci /* Okay to enable shared BW now */ 333862306a36Sopenharmony_ci data->valid_sections |= ICE_AQC_ELEM_VALID_SHARED; 333962306a36Sopenharmony_ci data->srl_id = cpu_to_le16(rl_prof_id); 334062306a36Sopenharmony_ci break; 334162306a36Sopenharmony_ci default: 334262306a36Sopenharmony_ci /* Unknown rate limit type */ 334362306a36Sopenharmony_ci return -EINVAL; 334462306a36Sopenharmony_ci } 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci /* Configure element */ 334762306a36Sopenharmony_ci return ice_sched_update_elem(hw, node, &buf); 334862306a36Sopenharmony_ci} 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci/** 335162306a36Sopenharmony_ci * ice_sched_get_node_rl_prof_id - get node's rate limit profile ID 335262306a36Sopenharmony_ci * @node: sched node 335362306a36Sopenharmony_ci * @rl_type: rate limit type 335462306a36Sopenharmony_ci * 335562306a36Sopenharmony_ci * If existing profile matches, it returns the corresponding rate 335662306a36Sopenharmony_ci * limit profile ID, otherwise it returns an invalid ID as error. 335762306a36Sopenharmony_ci */ 335862306a36Sopenharmony_cistatic u16 335962306a36Sopenharmony_ciice_sched_get_node_rl_prof_id(struct ice_sched_node *node, 336062306a36Sopenharmony_ci enum ice_rl_type rl_type) 336162306a36Sopenharmony_ci{ 336262306a36Sopenharmony_ci u16 rl_prof_id = ICE_SCHED_INVAL_PROF_ID; 336362306a36Sopenharmony_ci struct ice_aqc_txsched_elem *data; 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_ci data = &node->info.data; 336662306a36Sopenharmony_ci switch (rl_type) { 336762306a36Sopenharmony_ci case ICE_MIN_BW: 336862306a36Sopenharmony_ci if (data->valid_sections & ICE_AQC_ELEM_VALID_CIR) 336962306a36Sopenharmony_ci rl_prof_id = le16_to_cpu(data->cir_bw.bw_profile_idx); 337062306a36Sopenharmony_ci break; 337162306a36Sopenharmony_ci case ICE_MAX_BW: 337262306a36Sopenharmony_ci if (data->valid_sections & ICE_AQC_ELEM_VALID_EIR) 337362306a36Sopenharmony_ci rl_prof_id = le16_to_cpu(data->eir_bw.bw_profile_idx); 337462306a36Sopenharmony_ci break; 337562306a36Sopenharmony_ci case ICE_SHARED_BW: 337662306a36Sopenharmony_ci if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED) 337762306a36Sopenharmony_ci rl_prof_id = le16_to_cpu(data->srl_id); 337862306a36Sopenharmony_ci break; 337962306a36Sopenharmony_ci default: 338062306a36Sopenharmony_ci break; 338162306a36Sopenharmony_ci } 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci return rl_prof_id; 338462306a36Sopenharmony_ci} 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci/** 338762306a36Sopenharmony_ci * ice_sched_get_rl_prof_layer - selects rate limit profile creation layer 338862306a36Sopenharmony_ci * @pi: port information structure 338962306a36Sopenharmony_ci * @rl_type: type of rate limit BW - min, max, or shared 339062306a36Sopenharmony_ci * @layer_index: layer index 339162306a36Sopenharmony_ci * 339262306a36Sopenharmony_ci * This function returns requested profile creation layer. 339362306a36Sopenharmony_ci */ 339462306a36Sopenharmony_cistatic u8 339562306a36Sopenharmony_ciice_sched_get_rl_prof_layer(struct ice_port_info *pi, enum ice_rl_type rl_type, 339662306a36Sopenharmony_ci u8 layer_index) 339762306a36Sopenharmony_ci{ 339862306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 339962306a36Sopenharmony_ci 340062306a36Sopenharmony_ci if (layer_index >= hw->num_tx_sched_layers) 340162306a36Sopenharmony_ci return ICE_SCHED_INVAL_LAYER_NUM; 340262306a36Sopenharmony_ci switch (rl_type) { 340362306a36Sopenharmony_ci case ICE_MIN_BW: 340462306a36Sopenharmony_ci if (hw->layer_info[layer_index].max_cir_rl_profiles) 340562306a36Sopenharmony_ci return layer_index; 340662306a36Sopenharmony_ci break; 340762306a36Sopenharmony_ci case ICE_MAX_BW: 340862306a36Sopenharmony_ci if (hw->layer_info[layer_index].max_eir_rl_profiles) 340962306a36Sopenharmony_ci return layer_index; 341062306a36Sopenharmony_ci break; 341162306a36Sopenharmony_ci case ICE_SHARED_BW: 341262306a36Sopenharmony_ci /* if current layer doesn't support SRL profile creation 341362306a36Sopenharmony_ci * then try a layer up or down. 341462306a36Sopenharmony_ci */ 341562306a36Sopenharmony_ci if (hw->layer_info[layer_index].max_srl_profiles) 341662306a36Sopenharmony_ci return layer_index; 341762306a36Sopenharmony_ci else if (layer_index < hw->num_tx_sched_layers - 1 && 341862306a36Sopenharmony_ci hw->layer_info[layer_index + 1].max_srl_profiles) 341962306a36Sopenharmony_ci return layer_index + 1; 342062306a36Sopenharmony_ci else if (layer_index > 0 && 342162306a36Sopenharmony_ci hw->layer_info[layer_index - 1].max_srl_profiles) 342262306a36Sopenharmony_ci return layer_index - 1; 342362306a36Sopenharmony_ci break; 342462306a36Sopenharmony_ci default: 342562306a36Sopenharmony_ci break; 342662306a36Sopenharmony_ci } 342762306a36Sopenharmony_ci return ICE_SCHED_INVAL_LAYER_NUM; 342862306a36Sopenharmony_ci} 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci/** 343162306a36Sopenharmony_ci * ice_sched_get_srl_node - get shared rate limit node 343262306a36Sopenharmony_ci * @node: tree node 343362306a36Sopenharmony_ci * @srl_layer: shared rate limit layer 343462306a36Sopenharmony_ci * 343562306a36Sopenharmony_ci * This function returns SRL node to be used for shared rate limit purpose. 343662306a36Sopenharmony_ci * The caller needs to hold scheduler lock. 343762306a36Sopenharmony_ci */ 343862306a36Sopenharmony_cistatic struct ice_sched_node * 343962306a36Sopenharmony_ciice_sched_get_srl_node(struct ice_sched_node *node, u8 srl_layer) 344062306a36Sopenharmony_ci{ 344162306a36Sopenharmony_ci if (srl_layer > node->tx_sched_layer) 344262306a36Sopenharmony_ci return node->children[0]; 344362306a36Sopenharmony_ci else if (srl_layer < node->tx_sched_layer) 344462306a36Sopenharmony_ci /* Node can't be created without a parent. It will always 344562306a36Sopenharmony_ci * have a valid parent except root node. 344662306a36Sopenharmony_ci */ 344762306a36Sopenharmony_ci return node->parent; 344862306a36Sopenharmony_ci else 344962306a36Sopenharmony_ci return node; 345062306a36Sopenharmony_ci} 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci/** 345362306a36Sopenharmony_ci * ice_sched_rm_rl_profile - remove RL profile ID 345462306a36Sopenharmony_ci * @pi: port information structure 345562306a36Sopenharmony_ci * @layer_num: layer number where profiles are saved 345662306a36Sopenharmony_ci * @profile_type: profile type like EIR, CIR, or SRL 345762306a36Sopenharmony_ci * @profile_id: profile ID to remove 345862306a36Sopenharmony_ci * 345962306a36Sopenharmony_ci * This function removes rate limit profile from layer 'layer_num' of type 346062306a36Sopenharmony_ci * 'profile_type' and profile ID as 'profile_id'. The caller needs to hold 346162306a36Sopenharmony_ci * scheduler lock. 346262306a36Sopenharmony_ci */ 346362306a36Sopenharmony_cistatic int 346462306a36Sopenharmony_ciice_sched_rm_rl_profile(struct ice_port_info *pi, u8 layer_num, u8 profile_type, 346562306a36Sopenharmony_ci u16 profile_id) 346662306a36Sopenharmony_ci{ 346762306a36Sopenharmony_ci struct ice_aqc_rl_profile_info *rl_prof_elem; 346862306a36Sopenharmony_ci int status = 0; 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci if (layer_num >= ICE_AQC_TOPO_MAX_LEVEL_NUM) 347162306a36Sopenharmony_ci return -EINVAL; 347262306a36Sopenharmony_ci /* Check the existing list for RL profile */ 347362306a36Sopenharmony_ci list_for_each_entry(rl_prof_elem, &pi->rl_prof_list[layer_num], 347462306a36Sopenharmony_ci list_entry) 347562306a36Sopenharmony_ci if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) == 347662306a36Sopenharmony_ci profile_type && 347762306a36Sopenharmony_ci le16_to_cpu(rl_prof_elem->profile.profile_id) == 347862306a36Sopenharmony_ci profile_id) { 347962306a36Sopenharmony_ci if (rl_prof_elem->prof_id_ref) 348062306a36Sopenharmony_ci rl_prof_elem->prof_id_ref--; 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci /* Remove old profile ID from database */ 348362306a36Sopenharmony_ci status = ice_sched_del_rl_profile(pi->hw, rl_prof_elem); 348462306a36Sopenharmony_ci if (status && status != -EBUSY) 348562306a36Sopenharmony_ci ice_debug(pi->hw, ICE_DBG_SCHED, "Remove rl profile failed\n"); 348662306a36Sopenharmony_ci break; 348762306a36Sopenharmony_ci } 348862306a36Sopenharmony_ci if (status == -EBUSY) 348962306a36Sopenharmony_ci status = 0; 349062306a36Sopenharmony_ci return status; 349162306a36Sopenharmony_ci} 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci/** 349462306a36Sopenharmony_ci * ice_sched_set_node_bw_dflt - set node's bandwidth limit to default 349562306a36Sopenharmony_ci * @pi: port information structure 349662306a36Sopenharmony_ci * @node: pointer to node structure 349762306a36Sopenharmony_ci * @rl_type: rate limit type min, max, or shared 349862306a36Sopenharmony_ci * @layer_num: layer number where RL profiles are saved 349962306a36Sopenharmony_ci * 350062306a36Sopenharmony_ci * This function configures node element's BW rate limit profile ID of 350162306a36Sopenharmony_ci * type CIR, EIR, or SRL to default. This function needs to be called 350262306a36Sopenharmony_ci * with the scheduler lock held. 350362306a36Sopenharmony_ci */ 350462306a36Sopenharmony_cistatic int 350562306a36Sopenharmony_ciice_sched_set_node_bw_dflt(struct ice_port_info *pi, 350662306a36Sopenharmony_ci struct ice_sched_node *node, 350762306a36Sopenharmony_ci enum ice_rl_type rl_type, u8 layer_num) 350862306a36Sopenharmony_ci{ 350962306a36Sopenharmony_ci struct ice_hw *hw; 351062306a36Sopenharmony_ci u8 profile_type; 351162306a36Sopenharmony_ci u16 rl_prof_id; 351262306a36Sopenharmony_ci u16 old_id; 351362306a36Sopenharmony_ci int status; 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci hw = pi->hw; 351662306a36Sopenharmony_ci switch (rl_type) { 351762306a36Sopenharmony_ci case ICE_MIN_BW: 351862306a36Sopenharmony_ci profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR; 351962306a36Sopenharmony_ci rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID; 352062306a36Sopenharmony_ci break; 352162306a36Sopenharmony_ci case ICE_MAX_BW: 352262306a36Sopenharmony_ci profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR; 352362306a36Sopenharmony_ci rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID; 352462306a36Sopenharmony_ci break; 352562306a36Sopenharmony_ci case ICE_SHARED_BW: 352662306a36Sopenharmony_ci profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL; 352762306a36Sopenharmony_ci /* No SRL is configured for default case */ 352862306a36Sopenharmony_ci rl_prof_id = ICE_SCHED_NO_SHARED_RL_PROF_ID; 352962306a36Sopenharmony_ci break; 353062306a36Sopenharmony_ci default: 353162306a36Sopenharmony_ci return -EINVAL; 353262306a36Sopenharmony_ci } 353362306a36Sopenharmony_ci /* Save existing RL prof ID for later clean up */ 353462306a36Sopenharmony_ci old_id = ice_sched_get_node_rl_prof_id(node, rl_type); 353562306a36Sopenharmony_ci /* Configure BW scheduling parameters */ 353662306a36Sopenharmony_ci status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id); 353762306a36Sopenharmony_ci if (status) 353862306a36Sopenharmony_ci return status; 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci /* Remove stale RL profile ID */ 354162306a36Sopenharmony_ci if (old_id == ICE_SCHED_DFLT_RL_PROF_ID || 354262306a36Sopenharmony_ci old_id == ICE_SCHED_INVAL_PROF_ID) 354362306a36Sopenharmony_ci return 0; 354462306a36Sopenharmony_ci 354562306a36Sopenharmony_ci return ice_sched_rm_rl_profile(pi, layer_num, profile_type, old_id); 354662306a36Sopenharmony_ci} 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_ci/** 354962306a36Sopenharmony_ci * ice_sched_set_eir_srl_excl - set EIR/SRL exclusiveness 355062306a36Sopenharmony_ci * @pi: port information structure 355162306a36Sopenharmony_ci * @node: pointer to node structure 355262306a36Sopenharmony_ci * @layer_num: layer number where rate limit profiles are saved 355362306a36Sopenharmony_ci * @rl_type: rate limit type min, max, or shared 355462306a36Sopenharmony_ci * @bw: bandwidth value 355562306a36Sopenharmony_ci * 355662306a36Sopenharmony_ci * This function prepares node element's bandwidth to SRL or EIR exclusively. 355762306a36Sopenharmony_ci * EIR BW and Shared BW profiles are mutually exclusive and hence only one of 355862306a36Sopenharmony_ci * them may be set for any given element. This function needs to be called 355962306a36Sopenharmony_ci * with the scheduler lock held. 356062306a36Sopenharmony_ci */ 356162306a36Sopenharmony_cistatic int 356262306a36Sopenharmony_ciice_sched_set_eir_srl_excl(struct ice_port_info *pi, 356362306a36Sopenharmony_ci struct ice_sched_node *node, 356462306a36Sopenharmony_ci u8 layer_num, enum ice_rl_type rl_type, u32 bw) 356562306a36Sopenharmony_ci{ 356662306a36Sopenharmony_ci if (rl_type == ICE_SHARED_BW) { 356762306a36Sopenharmony_ci /* SRL node passed in this case, it may be different node */ 356862306a36Sopenharmony_ci if (bw == ICE_SCHED_DFLT_BW) 356962306a36Sopenharmony_ci /* SRL being removed, ice_sched_cfg_node_bw_lmt() 357062306a36Sopenharmony_ci * enables EIR to default. EIR is not set in this 357162306a36Sopenharmony_ci * case, so no additional action is required. 357262306a36Sopenharmony_ci */ 357362306a36Sopenharmony_ci return 0; 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci /* SRL being configured, set EIR to default here. 357662306a36Sopenharmony_ci * ice_sched_cfg_node_bw_lmt() disables EIR when it 357762306a36Sopenharmony_ci * configures SRL 357862306a36Sopenharmony_ci */ 357962306a36Sopenharmony_ci return ice_sched_set_node_bw_dflt(pi, node, ICE_MAX_BW, 358062306a36Sopenharmony_ci layer_num); 358162306a36Sopenharmony_ci } else if (rl_type == ICE_MAX_BW && 358262306a36Sopenharmony_ci node->info.data.valid_sections & ICE_AQC_ELEM_VALID_SHARED) { 358362306a36Sopenharmony_ci /* Remove Shared profile. Set default shared BW call 358462306a36Sopenharmony_ci * removes shared profile for a node. 358562306a36Sopenharmony_ci */ 358662306a36Sopenharmony_ci return ice_sched_set_node_bw_dflt(pi, node, 358762306a36Sopenharmony_ci ICE_SHARED_BW, 358862306a36Sopenharmony_ci layer_num); 358962306a36Sopenharmony_ci } 359062306a36Sopenharmony_ci return 0; 359162306a36Sopenharmony_ci} 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci/** 359462306a36Sopenharmony_ci * ice_sched_set_node_bw - set node's bandwidth 359562306a36Sopenharmony_ci * @pi: port information structure 359662306a36Sopenharmony_ci * @node: tree node 359762306a36Sopenharmony_ci * @rl_type: rate limit type min, max, or shared 359862306a36Sopenharmony_ci * @bw: bandwidth in Kbps - Kilo bits per sec 359962306a36Sopenharmony_ci * @layer_num: layer number 360062306a36Sopenharmony_ci * 360162306a36Sopenharmony_ci * This function adds new profile corresponding to requested BW, configures 360262306a36Sopenharmony_ci * node's RL profile ID of type CIR, EIR, or SRL, and removes old profile 360362306a36Sopenharmony_ci * ID from local database. The caller needs to hold scheduler lock. 360462306a36Sopenharmony_ci */ 360562306a36Sopenharmony_ciint 360662306a36Sopenharmony_ciice_sched_set_node_bw(struct ice_port_info *pi, struct ice_sched_node *node, 360762306a36Sopenharmony_ci enum ice_rl_type rl_type, u32 bw, u8 layer_num) 360862306a36Sopenharmony_ci{ 360962306a36Sopenharmony_ci struct ice_aqc_rl_profile_info *rl_prof_info; 361062306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 361162306a36Sopenharmony_ci u16 old_id, rl_prof_id; 361262306a36Sopenharmony_ci int status = -EINVAL; 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci rl_prof_info = ice_sched_add_rl_profile(pi, rl_type, bw, layer_num); 361562306a36Sopenharmony_ci if (!rl_prof_info) 361662306a36Sopenharmony_ci return status; 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci rl_prof_id = le16_to_cpu(rl_prof_info->profile.profile_id); 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci /* Save existing RL prof ID for later clean up */ 362162306a36Sopenharmony_ci old_id = ice_sched_get_node_rl_prof_id(node, rl_type); 362262306a36Sopenharmony_ci /* Configure BW scheduling parameters */ 362362306a36Sopenharmony_ci status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id); 362462306a36Sopenharmony_ci if (status) 362562306a36Sopenharmony_ci return status; 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci /* New changes has been applied */ 362862306a36Sopenharmony_ci /* Increment the profile ID reference count */ 362962306a36Sopenharmony_ci rl_prof_info->prof_id_ref++; 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci /* Check for old ID removal */ 363262306a36Sopenharmony_ci if ((old_id == ICE_SCHED_DFLT_RL_PROF_ID && rl_type != ICE_SHARED_BW) || 363362306a36Sopenharmony_ci old_id == ICE_SCHED_INVAL_PROF_ID || old_id == rl_prof_id) 363462306a36Sopenharmony_ci return 0; 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_ci return ice_sched_rm_rl_profile(pi, layer_num, 363762306a36Sopenharmony_ci rl_prof_info->profile.flags & 363862306a36Sopenharmony_ci ICE_AQC_RL_PROFILE_TYPE_M, old_id); 363962306a36Sopenharmony_ci} 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci/** 364262306a36Sopenharmony_ci * ice_sched_set_node_priority - set node's priority 364362306a36Sopenharmony_ci * @pi: port information structure 364462306a36Sopenharmony_ci * @node: tree node 364562306a36Sopenharmony_ci * @priority: number 0-7 representing priority among siblings 364662306a36Sopenharmony_ci * 364762306a36Sopenharmony_ci * This function sets priority of a node among it's siblings. 364862306a36Sopenharmony_ci */ 364962306a36Sopenharmony_ciint 365062306a36Sopenharmony_ciice_sched_set_node_priority(struct ice_port_info *pi, struct ice_sched_node *node, 365162306a36Sopenharmony_ci u16 priority) 365262306a36Sopenharmony_ci{ 365362306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data buf; 365462306a36Sopenharmony_ci struct ice_aqc_txsched_elem *data; 365562306a36Sopenharmony_ci 365662306a36Sopenharmony_ci buf = node->info; 365762306a36Sopenharmony_ci data = &buf.data; 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC; 366062306a36Sopenharmony_ci data->generic |= FIELD_PREP(ICE_AQC_ELEM_GENERIC_PRIO_M, priority); 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci return ice_sched_update_elem(pi->hw, node, &buf); 366362306a36Sopenharmony_ci} 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci/** 366662306a36Sopenharmony_ci * ice_sched_set_node_weight - set node's weight 366762306a36Sopenharmony_ci * @pi: port information structure 366862306a36Sopenharmony_ci * @node: tree node 366962306a36Sopenharmony_ci * @weight: number 1-200 representing weight for WFQ 367062306a36Sopenharmony_ci * 367162306a36Sopenharmony_ci * This function sets weight of the node for WFQ algorithm. 367262306a36Sopenharmony_ci */ 367362306a36Sopenharmony_ciint 367462306a36Sopenharmony_ciice_sched_set_node_weight(struct ice_port_info *pi, struct ice_sched_node *node, u16 weight) 367562306a36Sopenharmony_ci{ 367662306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data buf; 367762306a36Sopenharmony_ci struct ice_aqc_txsched_elem *data; 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_ci buf = node->info; 368062306a36Sopenharmony_ci data = &buf.data; 368162306a36Sopenharmony_ci 368262306a36Sopenharmony_ci data->valid_sections = ICE_AQC_ELEM_VALID_CIR | ICE_AQC_ELEM_VALID_EIR | 368362306a36Sopenharmony_ci ICE_AQC_ELEM_VALID_GENERIC; 368462306a36Sopenharmony_ci data->cir_bw.bw_alloc = cpu_to_le16(weight); 368562306a36Sopenharmony_ci data->eir_bw.bw_alloc = cpu_to_le16(weight); 368662306a36Sopenharmony_ci 368762306a36Sopenharmony_ci data->generic |= FIELD_PREP(ICE_AQC_ELEM_GENERIC_SP_M, 0x0); 368862306a36Sopenharmony_ci 368962306a36Sopenharmony_ci return ice_sched_update_elem(pi->hw, node, &buf); 369062306a36Sopenharmony_ci} 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci/** 369362306a36Sopenharmony_ci * ice_sched_set_node_bw_lmt - set node's BW limit 369462306a36Sopenharmony_ci * @pi: port information structure 369562306a36Sopenharmony_ci * @node: tree node 369662306a36Sopenharmony_ci * @rl_type: rate limit type min, max, or shared 369762306a36Sopenharmony_ci * @bw: bandwidth in Kbps - Kilo bits per sec 369862306a36Sopenharmony_ci * 369962306a36Sopenharmony_ci * It updates node's BW limit parameters like BW RL profile ID of type CIR, 370062306a36Sopenharmony_ci * EIR, or SRL. The caller needs to hold scheduler lock. 370162306a36Sopenharmony_ci */ 370262306a36Sopenharmony_ciint 370362306a36Sopenharmony_ciice_sched_set_node_bw_lmt(struct ice_port_info *pi, struct ice_sched_node *node, 370462306a36Sopenharmony_ci enum ice_rl_type rl_type, u32 bw) 370562306a36Sopenharmony_ci{ 370662306a36Sopenharmony_ci struct ice_sched_node *cfg_node = node; 370762306a36Sopenharmony_ci int status; 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci struct ice_hw *hw; 371062306a36Sopenharmony_ci u8 layer_num; 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci if (!pi) 371362306a36Sopenharmony_ci return -EINVAL; 371462306a36Sopenharmony_ci hw = pi->hw; 371562306a36Sopenharmony_ci /* Remove unused RL profile IDs from HW and SW DB */ 371662306a36Sopenharmony_ci ice_sched_rm_unused_rl_prof(pi); 371762306a36Sopenharmony_ci layer_num = ice_sched_get_rl_prof_layer(pi, rl_type, 371862306a36Sopenharmony_ci node->tx_sched_layer); 371962306a36Sopenharmony_ci if (layer_num >= hw->num_tx_sched_layers) 372062306a36Sopenharmony_ci return -EINVAL; 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_ci if (rl_type == ICE_SHARED_BW) { 372362306a36Sopenharmony_ci /* SRL node may be different */ 372462306a36Sopenharmony_ci cfg_node = ice_sched_get_srl_node(node, layer_num); 372562306a36Sopenharmony_ci if (!cfg_node) 372662306a36Sopenharmony_ci return -EIO; 372762306a36Sopenharmony_ci } 372862306a36Sopenharmony_ci /* EIR BW and Shared BW profiles are mutually exclusive and 372962306a36Sopenharmony_ci * hence only one of them may be set for any given element 373062306a36Sopenharmony_ci */ 373162306a36Sopenharmony_ci status = ice_sched_set_eir_srl_excl(pi, cfg_node, layer_num, rl_type, 373262306a36Sopenharmony_ci bw); 373362306a36Sopenharmony_ci if (status) 373462306a36Sopenharmony_ci return status; 373562306a36Sopenharmony_ci if (bw == ICE_SCHED_DFLT_BW) 373662306a36Sopenharmony_ci return ice_sched_set_node_bw_dflt(pi, cfg_node, rl_type, 373762306a36Sopenharmony_ci layer_num); 373862306a36Sopenharmony_ci return ice_sched_set_node_bw(pi, cfg_node, rl_type, bw, layer_num); 373962306a36Sopenharmony_ci} 374062306a36Sopenharmony_ci 374162306a36Sopenharmony_ci/** 374262306a36Sopenharmony_ci * ice_sched_set_node_bw_dflt_lmt - set node's BW limit to default 374362306a36Sopenharmony_ci * @pi: port information structure 374462306a36Sopenharmony_ci * @node: pointer to node structure 374562306a36Sopenharmony_ci * @rl_type: rate limit type min, max, or shared 374662306a36Sopenharmony_ci * 374762306a36Sopenharmony_ci * This function configures node element's BW rate limit profile ID of 374862306a36Sopenharmony_ci * type CIR, EIR, or SRL to default. This function needs to be called 374962306a36Sopenharmony_ci * with the scheduler lock held. 375062306a36Sopenharmony_ci */ 375162306a36Sopenharmony_cistatic int 375262306a36Sopenharmony_ciice_sched_set_node_bw_dflt_lmt(struct ice_port_info *pi, 375362306a36Sopenharmony_ci struct ice_sched_node *node, 375462306a36Sopenharmony_ci enum ice_rl_type rl_type) 375562306a36Sopenharmony_ci{ 375662306a36Sopenharmony_ci return ice_sched_set_node_bw_lmt(pi, node, rl_type, 375762306a36Sopenharmony_ci ICE_SCHED_DFLT_BW); 375862306a36Sopenharmony_ci} 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci/** 376162306a36Sopenharmony_ci * ice_sched_validate_srl_node - Check node for SRL applicability 376262306a36Sopenharmony_ci * @node: sched node to configure 376362306a36Sopenharmony_ci * @sel_layer: selected SRL layer 376462306a36Sopenharmony_ci * 376562306a36Sopenharmony_ci * This function checks if the SRL can be applied to a selected layer node on 376662306a36Sopenharmony_ci * behalf of the requested node (first argument). This function needs to be 376762306a36Sopenharmony_ci * called with scheduler lock held. 376862306a36Sopenharmony_ci */ 376962306a36Sopenharmony_cistatic int 377062306a36Sopenharmony_ciice_sched_validate_srl_node(struct ice_sched_node *node, u8 sel_layer) 377162306a36Sopenharmony_ci{ 377262306a36Sopenharmony_ci /* SRL profiles are not available on all layers. Check if the 377362306a36Sopenharmony_ci * SRL profile can be applied to a node above or below the 377462306a36Sopenharmony_ci * requested node. SRL configuration is possible only if the 377562306a36Sopenharmony_ci * selected layer's node has single child. 377662306a36Sopenharmony_ci */ 377762306a36Sopenharmony_ci if (sel_layer == node->tx_sched_layer || 377862306a36Sopenharmony_ci ((sel_layer == node->tx_sched_layer + 1) && 377962306a36Sopenharmony_ci node->num_children == 1) || 378062306a36Sopenharmony_ci ((sel_layer == node->tx_sched_layer - 1) && 378162306a36Sopenharmony_ci (node->parent && node->parent->num_children == 1))) 378262306a36Sopenharmony_ci return 0; 378362306a36Sopenharmony_ci 378462306a36Sopenharmony_ci return -EIO; 378562306a36Sopenharmony_ci} 378662306a36Sopenharmony_ci 378762306a36Sopenharmony_ci/** 378862306a36Sopenharmony_ci * ice_sched_save_q_bw - save queue node's BW information 378962306a36Sopenharmony_ci * @q_ctx: queue context structure 379062306a36Sopenharmony_ci * @rl_type: rate limit type min, max, or shared 379162306a36Sopenharmony_ci * @bw: bandwidth in Kbps - Kilo bits per sec 379262306a36Sopenharmony_ci * 379362306a36Sopenharmony_ci * Save BW information of queue type node for post replay use. 379462306a36Sopenharmony_ci */ 379562306a36Sopenharmony_cistatic int 379662306a36Sopenharmony_ciice_sched_save_q_bw(struct ice_q_ctx *q_ctx, enum ice_rl_type rl_type, u32 bw) 379762306a36Sopenharmony_ci{ 379862306a36Sopenharmony_ci switch (rl_type) { 379962306a36Sopenharmony_ci case ICE_MIN_BW: 380062306a36Sopenharmony_ci ice_set_clear_cir_bw(&q_ctx->bw_t_info, bw); 380162306a36Sopenharmony_ci break; 380262306a36Sopenharmony_ci case ICE_MAX_BW: 380362306a36Sopenharmony_ci ice_set_clear_eir_bw(&q_ctx->bw_t_info, bw); 380462306a36Sopenharmony_ci break; 380562306a36Sopenharmony_ci case ICE_SHARED_BW: 380662306a36Sopenharmony_ci ice_set_clear_shared_bw(&q_ctx->bw_t_info, bw); 380762306a36Sopenharmony_ci break; 380862306a36Sopenharmony_ci default: 380962306a36Sopenharmony_ci return -EINVAL; 381062306a36Sopenharmony_ci } 381162306a36Sopenharmony_ci return 0; 381262306a36Sopenharmony_ci} 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci/** 381562306a36Sopenharmony_ci * ice_sched_set_q_bw_lmt - sets queue BW limit 381662306a36Sopenharmony_ci * @pi: port information structure 381762306a36Sopenharmony_ci * @vsi_handle: sw VSI handle 381862306a36Sopenharmony_ci * @tc: traffic class 381962306a36Sopenharmony_ci * @q_handle: software queue handle 382062306a36Sopenharmony_ci * @rl_type: min, max, or shared 382162306a36Sopenharmony_ci * @bw: bandwidth in Kbps 382262306a36Sopenharmony_ci * 382362306a36Sopenharmony_ci * This function sets BW limit of queue scheduling node. 382462306a36Sopenharmony_ci */ 382562306a36Sopenharmony_cistatic int 382662306a36Sopenharmony_ciice_sched_set_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 382762306a36Sopenharmony_ci u16 q_handle, enum ice_rl_type rl_type, u32 bw) 382862306a36Sopenharmony_ci{ 382962306a36Sopenharmony_ci struct ice_sched_node *node; 383062306a36Sopenharmony_ci struct ice_q_ctx *q_ctx; 383162306a36Sopenharmony_ci int status = -EINVAL; 383262306a36Sopenharmony_ci 383362306a36Sopenharmony_ci if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 383462306a36Sopenharmony_ci return -EINVAL; 383562306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 383662306a36Sopenharmony_ci q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handle); 383762306a36Sopenharmony_ci if (!q_ctx) 383862306a36Sopenharmony_ci goto exit_q_bw_lmt; 383962306a36Sopenharmony_ci node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid); 384062306a36Sopenharmony_ci if (!node) { 384162306a36Sopenharmony_ci ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong q_teid\n"); 384262306a36Sopenharmony_ci goto exit_q_bw_lmt; 384362306a36Sopenharmony_ci } 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci /* Return error if it is not a leaf node */ 384662306a36Sopenharmony_ci if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) 384762306a36Sopenharmony_ci goto exit_q_bw_lmt; 384862306a36Sopenharmony_ci 384962306a36Sopenharmony_ci /* SRL bandwidth layer selection */ 385062306a36Sopenharmony_ci if (rl_type == ICE_SHARED_BW) { 385162306a36Sopenharmony_ci u8 sel_layer; /* selected layer */ 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci sel_layer = ice_sched_get_rl_prof_layer(pi, rl_type, 385462306a36Sopenharmony_ci node->tx_sched_layer); 385562306a36Sopenharmony_ci if (sel_layer >= pi->hw->num_tx_sched_layers) { 385662306a36Sopenharmony_ci status = -EINVAL; 385762306a36Sopenharmony_ci goto exit_q_bw_lmt; 385862306a36Sopenharmony_ci } 385962306a36Sopenharmony_ci status = ice_sched_validate_srl_node(node, sel_layer); 386062306a36Sopenharmony_ci if (status) 386162306a36Sopenharmony_ci goto exit_q_bw_lmt; 386262306a36Sopenharmony_ci } 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_ci if (bw == ICE_SCHED_DFLT_BW) 386562306a36Sopenharmony_ci status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type); 386662306a36Sopenharmony_ci else 386762306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw); 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci if (!status) 387062306a36Sopenharmony_ci status = ice_sched_save_q_bw(q_ctx, rl_type, bw); 387162306a36Sopenharmony_ci 387262306a36Sopenharmony_ciexit_q_bw_lmt: 387362306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 387462306a36Sopenharmony_ci return status; 387562306a36Sopenharmony_ci} 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci/** 387862306a36Sopenharmony_ci * ice_cfg_q_bw_lmt - configure queue BW limit 387962306a36Sopenharmony_ci * @pi: port information structure 388062306a36Sopenharmony_ci * @vsi_handle: sw VSI handle 388162306a36Sopenharmony_ci * @tc: traffic class 388262306a36Sopenharmony_ci * @q_handle: software queue handle 388362306a36Sopenharmony_ci * @rl_type: min, max, or shared 388462306a36Sopenharmony_ci * @bw: bandwidth in Kbps 388562306a36Sopenharmony_ci * 388662306a36Sopenharmony_ci * This function configures BW limit of queue scheduling node. 388762306a36Sopenharmony_ci */ 388862306a36Sopenharmony_ciint 388962306a36Sopenharmony_ciice_cfg_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 389062306a36Sopenharmony_ci u16 q_handle, enum ice_rl_type rl_type, u32 bw) 389162306a36Sopenharmony_ci{ 389262306a36Sopenharmony_ci return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type, 389362306a36Sopenharmony_ci bw); 389462306a36Sopenharmony_ci} 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci/** 389762306a36Sopenharmony_ci * ice_cfg_q_bw_dflt_lmt - configure queue BW default limit 389862306a36Sopenharmony_ci * @pi: port information structure 389962306a36Sopenharmony_ci * @vsi_handle: sw VSI handle 390062306a36Sopenharmony_ci * @tc: traffic class 390162306a36Sopenharmony_ci * @q_handle: software queue handle 390262306a36Sopenharmony_ci * @rl_type: min, max, or shared 390362306a36Sopenharmony_ci * 390462306a36Sopenharmony_ci * This function configures BW default limit of queue scheduling node. 390562306a36Sopenharmony_ci */ 390662306a36Sopenharmony_ciint 390762306a36Sopenharmony_ciice_cfg_q_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 390862306a36Sopenharmony_ci u16 q_handle, enum ice_rl_type rl_type) 390962306a36Sopenharmony_ci{ 391062306a36Sopenharmony_ci return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type, 391162306a36Sopenharmony_ci ICE_SCHED_DFLT_BW); 391262306a36Sopenharmony_ci} 391362306a36Sopenharmony_ci 391462306a36Sopenharmony_ci/** 391562306a36Sopenharmony_ci * ice_sched_get_node_by_id_type - get node from ID type 391662306a36Sopenharmony_ci * @pi: port information structure 391762306a36Sopenharmony_ci * @id: identifier 391862306a36Sopenharmony_ci * @agg_type: type of aggregator 391962306a36Sopenharmony_ci * @tc: traffic class 392062306a36Sopenharmony_ci * 392162306a36Sopenharmony_ci * This function returns node identified by ID of type aggregator, and 392262306a36Sopenharmony_ci * based on traffic class (TC). This function needs to be called with 392362306a36Sopenharmony_ci * the scheduler lock held. 392462306a36Sopenharmony_ci */ 392562306a36Sopenharmony_cistatic struct ice_sched_node * 392662306a36Sopenharmony_ciice_sched_get_node_by_id_type(struct ice_port_info *pi, u32 id, 392762306a36Sopenharmony_ci enum ice_agg_type agg_type, u8 tc) 392862306a36Sopenharmony_ci{ 392962306a36Sopenharmony_ci struct ice_sched_node *node = NULL; 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci switch (agg_type) { 393262306a36Sopenharmony_ci case ICE_AGG_TYPE_VSI: { 393362306a36Sopenharmony_ci struct ice_vsi_ctx *vsi_ctx; 393462306a36Sopenharmony_ci u16 vsi_handle = (u16)id; 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 393762306a36Sopenharmony_ci break; 393862306a36Sopenharmony_ci /* Get sched_vsi_info */ 393962306a36Sopenharmony_ci vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 394062306a36Sopenharmony_ci if (!vsi_ctx) 394162306a36Sopenharmony_ci break; 394262306a36Sopenharmony_ci node = vsi_ctx->sched.vsi_node[tc]; 394362306a36Sopenharmony_ci break; 394462306a36Sopenharmony_ci } 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci case ICE_AGG_TYPE_AGG: { 394762306a36Sopenharmony_ci struct ice_sched_node *tc_node; 394862306a36Sopenharmony_ci 394962306a36Sopenharmony_ci tc_node = ice_sched_get_tc_node(pi, tc); 395062306a36Sopenharmony_ci if (tc_node) 395162306a36Sopenharmony_ci node = ice_sched_get_agg_node(pi, tc_node, id); 395262306a36Sopenharmony_ci break; 395362306a36Sopenharmony_ci } 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_ci default: 395662306a36Sopenharmony_ci break; 395762306a36Sopenharmony_ci } 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci return node; 396062306a36Sopenharmony_ci} 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci/** 396362306a36Sopenharmony_ci * ice_sched_set_node_bw_lmt_per_tc - set node BW limit per TC 396462306a36Sopenharmony_ci * @pi: port information structure 396562306a36Sopenharmony_ci * @id: ID (software VSI handle or AGG ID) 396662306a36Sopenharmony_ci * @agg_type: aggregator type (VSI or AGG type node) 396762306a36Sopenharmony_ci * @tc: traffic class 396862306a36Sopenharmony_ci * @rl_type: min or max 396962306a36Sopenharmony_ci * @bw: bandwidth in Kbps 397062306a36Sopenharmony_ci * 397162306a36Sopenharmony_ci * This function sets BW limit of VSI or Aggregator scheduling node 397262306a36Sopenharmony_ci * based on TC information from passed in argument BW. 397362306a36Sopenharmony_ci */ 397462306a36Sopenharmony_cistatic int 397562306a36Sopenharmony_ciice_sched_set_node_bw_lmt_per_tc(struct ice_port_info *pi, u32 id, 397662306a36Sopenharmony_ci enum ice_agg_type agg_type, u8 tc, 397762306a36Sopenharmony_ci enum ice_rl_type rl_type, u32 bw) 397862306a36Sopenharmony_ci{ 397962306a36Sopenharmony_ci struct ice_sched_node *node; 398062306a36Sopenharmony_ci int status = -EINVAL; 398162306a36Sopenharmony_ci 398262306a36Sopenharmony_ci if (!pi) 398362306a36Sopenharmony_ci return status; 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci if (rl_type == ICE_UNKNOWN_BW) 398662306a36Sopenharmony_ci return status; 398762306a36Sopenharmony_ci 398862306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 398962306a36Sopenharmony_ci node = ice_sched_get_node_by_id_type(pi, id, agg_type, tc); 399062306a36Sopenharmony_ci if (!node) { 399162306a36Sopenharmony_ci ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong id, agg type, or tc\n"); 399262306a36Sopenharmony_ci goto exit_set_node_bw_lmt_per_tc; 399362306a36Sopenharmony_ci } 399462306a36Sopenharmony_ci if (bw == ICE_SCHED_DFLT_BW) 399562306a36Sopenharmony_ci status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type); 399662306a36Sopenharmony_ci else 399762306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw); 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ciexit_set_node_bw_lmt_per_tc: 400062306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 400162306a36Sopenharmony_ci return status; 400262306a36Sopenharmony_ci} 400362306a36Sopenharmony_ci 400462306a36Sopenharmony_ci/** 400562306a36Sopenharmony_ci * ice_cfg_vsi_bw_lmt_per_tc - configure VSI BW limit per TC 400662306a36Sopenharmony_ci * @pi: port information structure 400762306a36Sopenharmony_ci * @vsi_handle: software VSI handle 400862306a36Sopenharmony_ci * @tc: traffic class 400962306a36Sopenharmony_ci * @rl_type: min or max 401062306a36Sopenharmony_ci * @bw: bandwidth in Kbps 401162306a36Sopenharmony_ci * 401262306a36Sopenharmony_ci * This function configures BW limit of VSI scheduling node based on TC 401362306a36Sopenharmony_ci * information. 401462306a36Sopenharmony_ci */ 401562306a36Sopenharmony_ciint 401662306a36Sopenharmony_ciice_cfg_vsi_bw_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 401762306a36Sopenharmony_ci enum ice_rl_type rl_type, u32 bw) 401862306a36Sopenharmony_ci{ 401962306a36Sopenharmony_ci int status; 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle, 402262306a36Sopenharmony_ci ICE_AGG_TYPE_VSI, 402362306a36Sopenharmony_ci tc, rl_type, bw); 402462306a36Sopenharmony_ci if (!status) { 402562306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 402662306a36Sopenharmony_ci status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, bw); 402762306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 402862306a36Sopenharmony_ci } 402962306a36Sopenharmony_ci return status; 403062306a36Sopenharmony_ci} 403162306a36Sopenharmony_ci 403262306a36Sopenharmony_ci/** 403362306a36Sopenharmony_ci * ice_cfg_vsi_bw_dflt_lmt_per_tc - configure default VSI BW limit per TC 403462306a36Sopenharmony_ci * @pi: port information structure 403562306a36Sopenharmony_ci * @vsi_handle: software VSI handle 403662306a36Sopenharmony_ci * @tc: traffic class 403762306a36Sopenharmony_ci * @rl_type: min or max 403862306a36Sopenharmony_ci * 403962306a36Sopenharmony_ci * This function configures default BW limit of VSI scheduling node based on TC 404062306a36Sopenharmony_ci * information. 404162306a36Sopenharmony_ci */ 404262306a36Sopenharmony_ciint 404362306a36Sopenharmony_ciice_cfg_vsi_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 404462306a36Sopenharmony_ci enum ice_rl_type rl_type) 404562306a36Sopenharmony_ci{ 404662306a36Sopenharmony_ci int status; 404762306a36Sopenharmony_ci 404862306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle, 404962306a36Sopenharmony_ci ICE_AGG_TYPE_VSI, 405062306a36Sopenharmony_ci tc, rl_type, 405162306a36Sopenharmony_ci ICE_SCHED_DFLT_BW); 405262306a36Sopenharmony_ci if (!status) { 405362306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 405462306a36Sopenharmony_ci status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, 405562306a36Sopenharmony_ci ICE_SCHED_DFLT_BW); 405662306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 405762306a36Sopenharmony_ci } 405862306a36Sopenharmony_ci return status; 405962306a36Sopenharmony_ci} 406062306a36Sopenharmony_ci 406162306a36Sopenharmony_ci/** 406262306a36Sopenharmony_ci * ice_cfg_rl_burst_size - Set burst size value 406362306a36Sopenharmony_ci * @hw: pointer to the HW struct 406462306a36Sopenharmony_ci * @bytes: burst size in bytes 406562306a36Sopenharmony_ci * 406662306a36Sopenharmony_ci * This function configures/set the burst size to requested new value. The new 406762306a36Sopenharmony_ci * burst size value is used for future rate limit calls. It doesn't change the 406862306a36Sopenharmony_ci * existing or previously created RL profiles. 406962306a36Sopenharmony_ci */ 407062306a36Sopenharmony_ciint ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes) 407162306a36Sopenharmony_ci{ 407262306a36Sopenharmony_ci u16 burst_size_to_prog; 407362306a36Sopenharmony_ci 407462306a36Sopenharmony_ci if (bytes < ICE_MIN_BURST_SIZE_ALLOWED || 407562306a36Sopenharmony_ci bytes > ICE_MAX_BURST_SIZE_ALLOWED) 407662306a36Sopenharmony_ci return -EINVAL; 407762306a36Sopenharmony_ci if (ice_round_to_num(bytes, 64) <= 407862306a36Sopenharmony_ci ICE_MAX_BURST_SIZE_64_BYTE_GRANULARITY) { 407962306a36Sopenharmony_ci /* 64 byte granularity case */ 408062306a36Sopenharmony_ci /* Disable MSB granularity bit */ 408162306a36Sopenharmony_ci burst_size_to_prog = ICE_64_BYTE_GRANULARITY; 408262306a36Sopenharmony_ci /* round number to nearest 64 byte granularity */ 408362306a36Sopenharmony_ci bytes = ice_round_to_num(bytes, 64); 408462306a36Sopenharmony_ci /* The value is in 64 byte chunks */ 408562306a36Sopenharmony_ci burst_size_to_prog |= (u16)(bytes / 64); 408662306a36Sopenharmony_ci } else { 408762306a36Sopenharmony_ci /* k bytes granularity case */ 408862306a36Sopenharmony_ci /* Enable MSB granularity bit */ 408962306a36Sopenharmony_ci burst_size_to_prog = ICE_KBYTE_GRANULARITY; 409062306a36Sopenharmony_ci /* round number to nearest 1024 granularity */ 409162306a36Sopenharmony_ci bytes = ice_round_to_num(bytes, 1024); 409262306a36Sopenharmony_ci /* check rounding doesn't go beyond allowed */ 409362306a36Sopenharmony_ci if (bytes > ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY) 409462306a36Sopenharmony_ci bytes = ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY; 409562306a36Sopenharmony_ci /* The value is in k bytes */ 409662306a36Sopenharmony_ci burst_size_to_prog |= (u16)(bytes / 1024); 409762306a36Sopenharmony_ci } 409862306a36Sopenharmony_ci hw->max_burst_size = burst_size_to_prog; 409962306a36Sopenharmony_ci return 0; 410062306a36Sopenharmony_ci} 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_ci/** 410362306a36Sopenharmony_ci * ice_sched_replay_node_prio - re-configure node priority 410462306a36Sopenharmony_ci * @hw: pointer to the HW struct 410562306a36Sopenharmony_ci * @node: sched node to configure 410662306a36Sopenharmony_ci * @priority: priority value 410762306a36Sopenharmony_ci * 410862306a36Sopenharmony_ci * This function configures node element's priority value. It 410962306a36Sopenharmony_ci * needs to be called with scheduler lock held. 411062306a36Sopenharmony_ci */ 411162306a36Sopenharmony_cistatic int 411262306a36Sopenharmony_ciice_sched_replay_node_prio(struct ice_hw *hw, struct ice_sched_node *node, 411362306a36Sopenharmony_ci u8 priority) 411462306a36Sopenharmony_ci{ 411562306a36Sopenharmony_ci struct ice_aqc_txsched_elem_data buf; 411662306a36Sopenharmony_ci struct ice_aqc_txsched_elem *data; 411762306a36Sopenharmony_ci int status; 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_ci buf = node->info; 412062306a36Sopenharmony_ci data = &buf.data; 412162306a36Sopenharmony_ci data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC; 412262306a36Sopenharmony_ci data->generic = priority; 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_ci /* Configure element */ 412562306a36Sopenharmony_ci status = ice_sched_update_elem(hw, node, &buf); 412662306a36Sopenharmony_ci return status; 412762306a36Sopenharmony_ci} 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_ci/** 413062306a36Sopenharmony_ci * ice_sched_replay_node_bw - replay node(s) BW 413162306a36Sopenharmony_ci * @hw: pointer to the HW struct 413262306a36Sopenharmony_ci * @node: sched node to configure 413362306a36Sopenharmony_ci * @bw_t_info: BW type information 413462306a36Sopenharmony_ci * 413562306a36Sopenharmony_ci * This function restores node's BW from bw_t_info. The caller needs 413662306a36Sopenharmony_ci * to hold the scheduler lock. 413762306a36Sopenharmony_ci */ 413862306a36Sopenharmony_cistatic int 413962306a36Sopenharmony_ciice_sched_replay_node_bw(struct ice_hw *hw, struct ice_sched_node *node, 414062306a36Sopenharmony_ci struct ice_bw_type_info *bw_t_info) 414162306a36Sopenharmony_ci{ 414262306a36Sopenharmony_ci struct ice_port_info *pi = hw->port_info; 414362306a36Sopenharmony_ci int status = -EINVAL; 414462306a36Sopenharmony_ci u16 bw_alloc; 414562306a36Sopenharmony_ci 414662306a36Sopenharmony_ci if (!node) 414762306a36Sopenharmony_ci return status; 414862306a36Sopenharmony_ci if (bitmap_empty(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CNT)) 414962306a36Sopenharmony_ci return 0; 415062306a36Sopenharmony_ci if (test_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap)) { 415162306a36Sopenharmony_ci status = ice_sched_replay_node_prio(hw, node, 415262306a36Sopenharmony_ci bw_t_info->generic); 415362306a36Sopenharmony_ci if (status) 415462306a36Sopenharmony_ci return status; 415562306a36Sopenharmony_ci } 415662306a36Sopenharmony_ci if (test_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap)) { 415762306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt(pi, node, ICE_MIN_BW, 415862306a36Sopenharmony_ci bw_t_info->cir_bw.bw); 415962306a36Sopenharmony_ci if (status) 416062306a36Sopenharmony_ci return status; 416162306a36Sopenharmony_ci } 416262306a36Sopenharmony_ci if (test_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap)) { 416362306a36Sopenharmony_ci bw_alloc = bw_t_info->cir_bw.bw_alloc; 416462306a36Sopenharmony_ci status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MIN_BW, 416562306a36Sopenharmony_ci bw_alloc); 416662306a36Sopenharmony_ci if (status) 416762306a36Sopenharmony_ci return status; 416862306a36Sopenharmony_ci } 416962306a36Sopenharmony_ci if (test_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap)) { 417062306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt(pi, node, ICE_MAX_BW, 417162306a36Sopenharmony_ci bw_t_info->eir_bw.bw); 417262306a36Sopenharmony_ci if (status) 417362306a36Sopenharmony_ci return status; 417462306a36Sopenharmony_ci } 417562306a36Sopenharmony_ci if (test_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap)) { 417662306a36Sopenharmony_ci bw_alloc = bw_t_info->eir_bw.bw_alloc; 417762306a36Sopenharmony_ci status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MAX_BW, 417862306a36Sopenharmony_ci bw_alloc); 417962306a36Sopenharmony_ci if (status) 418062306a36Sopenharmony_ci return status; 418162306a36Sopenharmony_ci } 418262306a36Sopenharmony_ci if (test_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap)) 418362306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt(pi, node, ICE_SHARED_BW, 418462306a36Sopenharmony_ci bw_t_info->shared_bw); 418562306a36Sopenharmony_ci return status; 418662306a36Sopenharmony_ci} 418762306a36Sopenharmony_ci 418862306a36Sopenharmony_ci/** 418962306a36Sopenharmony_ci * ice_sched_get_ena_tc_bitmap - get enabled TC bitmap 419062306a36Sopenharmony_ci * @pi: port info struct 419162306a36Sopenharmony_ci * @tc_bitmap: 8 bits TC bitmap to check 419262306a36Sopenharmony_ci * @ena_tc_bitmap: 8 bits enabled TC bitmap to return 419362306a36Sopenharmony_ci * 419462306a36Sopenharmony_ci * This function returns enabled TC bitmap in variable ena_tc_bitmap. Some TCs 419562306a36Sopenharmony_ci * may be missing, it returns enabled TCs. This function needs to be called with 419662306a36Sopenharmony_ci * scheduler lock held. 419762306a36Sopenharmony_ci */ 419862306a36Sopenharmony_cistatic void 419962306a36Sopenharmony_ciice_sched_get_ena_tc_bitmap(struct ice_port_info *pi, 420062306a36Sopenharmony_ci unsigned long *tc_bitmap, 420162306a36Sopenharmony_ci unsigned long *ena_tc_bitmap) 420262306a36Sopenharmony_ci{ 420362306a36Sopenharmony_ci u8 tc; 420462306a36Sopenharmony_ci 420562306a36Sopenharmony_ci /* Some TC(s) may be missing after reset, adjust for replay */ 420662306a36Sopenharmony_ci ice_for_each_traffic_class(tc) 420762306a36Sopenharmony_ci if (ice_is_tc_ena(*tc_bitmap, tc) && 420862306a36Sopenharmony_ci (ice_sched_get_tc_node(pi, tc))) 420962306a36Sopenharmony_ci set_bit(tc, ena_tc_bitmap); 421062306a36Sopenharmony_ci} 421162306a36Sopenharmony_ci 421262306a36Sopenharmony_ci/** 421362306a36Sopenharmony_ci * ice_sched_replay_agg - recreate aggregator node(s) 421462306a36Sopenharmony_ci * @hw: pointer to the HW struct 421562306a36Sopenharmony_ci * 421662306a36Sopenharmony_ci * This function recreate aggregator type nodes which are not replayed earlier. 421762306a36Sopenharmony_ci * It also replay aggregator BW information. These aggregator nodes are not 421862306a36Sopenharmony_ci * associated with VSI type node yet. 421962306a36Sopenharmony_ci */ 422062306a36Sopenharmony_civoid ice_sched_replay_agg(struct ice_hw *hw) 422162306a36Sopenharmony_ci{ 422262306a36Sopenharmony_ci struct ice_port_info *pi = hw->port_info; 422362306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 422462306a36Sopenharmony_ci 422562306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 422662306a36Sopenharmony_ci list_for_each_entry(agg_info, &hw->agg_list, list_entry) 422762306a36Sopenharmony_ci /* replay aggregator (re-create aggregator node) */ 422862306a36Sopenharmony_ci if (!bitmap_equal(agg_info->tc_bitmap, agg_info->replay_tc_bitmap, 422962306a36Sopenharmony_ci ICE_MAX_TRAFFIC_CLASS)) { 423062306a36Sopenharmony_ci DECLARE_BITMAP(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 423162306a36Sopenharmony_ci int status; 423262306a36Sopenharmony_ci 423362306a36Sopenharmony_ci bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 423462306a36Sopenharmony_ci ice_sched_get_ena_tc_bitmap(pi, 423562306a36Sopenharmony_ci agg_info->replay_tc_bitmap, 423662306a36Sopenharmony_ci replay_bitmap); 423762306a36Sopenharmony_ci status = ice_sched_cfg_agg(hw->port_info, 423862306a36Sopenharmony_ci agg_info->agg_id, 423962306a36Sopenharmony_ci ICE_AGG_TYPE_AGG, 424062306a36Sopenharmony_ci replay_bitmap); 424162306a36Sopenharmony_ci if (status) { 424262306a36Sopenharmony_ci dev_info(ice_hw_to_dev(hw), 424362306a36Sopenharmony_ci "Replay agg id[%d] failed\n", 424462306a36Sopenharmony_ci agg_info->agg_id); 424562306a36Sopenharmony_ci /* Move on to next one */ 424662306a36Sopenharmony_ci continue; 424762306a36Sopenharmony_ci } 424862306a36Sopenharmony_ci } 424962306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 425062306a36Sopenharmony_ci} 425162306a36Sopenharmony_ci 425262306a36Sopenharmony_ci/** 425362306a36Sopenharmony_ci * ice_sched_replay_agg_vsi_preinit - Agg/VSI replay pre initialization 425462306a36Sopenharmony_ci * @hw: pointer to the HW struct 425562306a36Sopenharmony_ci * 425662306a36Sopenharmony_ci * This function initialize aggregator(s) TC bitmap to zero. A required 425762306a36Sopenharmony_ci * preinit step for replaying aggregators. 425862306a36Sopenharmony_ci */ 425962306a36Sopenharmony_civoid ice_sched_replay_agg_vsi_preinit(struct ice_hw *hw) 426062306a36Sopenharmony_ci{ 426162306a36Sopenharmony_ci struct ice_port_info *pi = hw->port_info; 426262306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 426562306a36Sopenharmony_ci list_for_each_entry(agg_info, &hw->agg_list, list_entry) { 426662306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info; 426762306a36Sopenharmony_ci 426862306a36Sopenharmony_ci agg_info->tc_bitmap[0] = 0; 426962306a36Sopenharmony_ci list_for_each_entry(agg_vsi_info, &agg_info->agg_vsi_list, 427062306a36Sopenharmony_ci list_entry) 427162306a36Sopenharmony_ci agg_vsi_info->tc_bitmap[0] = 0; 427262306a36Sopenharmony_ci } 427362306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 427462306a36Sopenharmony_ci} 427562306a36Sopenharmony_ci 427662306a36Sopenharmony_ci/** 427762306a36Sopenharmony_ci * ice_sched_replay_vsi_agg - replay aggregator & VSI to aggregator node(s) 427862306a36Sopenharmony_ci * @hw: pointer to the HW struct 427962306a36Sopenharmony_ci * @vsi_handle: software VSI handle 428062306a36Sopenharmony_ci * 428162306a36Sopenharmony_ci * This function replays aggregator node, VSI to aggregator type nodes, and 428262306a36Sopenharmony_ci * their node bandwidth information. This function needs to be called with 428362306a36Sopenharmony_ci * scheduler lock held. 428462306a36Sopenharmony_ci */ 428562306a36Sopenharmony_cistatic int ice_sched_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle) 428662306a36Sopenharmony_ci{ 428762306a36Sopenharmony_ci DECLARE_BITMAP(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 428862306a36Sopenharmony_ci struct ice_sched_agg_vsi_info *agg_vsi_info; 428962306a36Sopenharmony_ci struct ice_port_info *pi = hw->port_info; 429062306a36Sopenharmony_ci struct ice_sched_agg_info *agg_info; 429162306a36Sopenharmony_ci int status; 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_ci bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 429462306a36Sopenharmony_ci if (!ice_is_vsi_valid(hw, vsi_handle)) 429562306a36Sopenharmony_ci return -EINVAL; 429662306a36Sopenharmony_ci agg_info = ice_get_vsi_agg_info(hw, vsi_handle); 429762306a36Sopenharmony_ci if (!agg_info) 429862306a36Sopenharmony_ci return 0; /* Not present in list - default Agg case */ 429962306a36Sopenharmony_ci agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle); 430062306a36Sopenharmony_ci if (!agg_vsi_info) 430162306a36Sopenharmony_ci return 0; /* Not present in list - default Agg case */ 430262306a36Sopenharmony_ci ice_sched_get_ena_tc_bitmap(pi, agg_info->replay_tc_bitmap, 430362306a36Sopenharmony_ci replay_bitmap); 430462306a36Sopenharmony_ci /* Replay aggregator node associated to vsi_handle */ 430562306a36Sopenharmony_ci status = ice_sched_cfg_agg(hw->port_info, agg_info->agg_id, 430662306a36Sopenharmony_ci ICE_AGG_TYPE_AGG, replay_bitmap); 430762306a36Sopenharmony_ci if (status) 430862306a36Sopenharmony_ci return status; 430962306a36Sopenharmony_ci 431062306a36Sopenharmony_ci bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 431162306a36Sopenharmony_ci ice_sched_get_ena_tc_bitmap(pi, agg_vsi_info->replay_tc_bitmap, 431262306a36Sopenharmony_ci replay_bitmap); 431362306a36Sopenharmony_ci /* Move this VSI (vsi_handle) to above aggregator */ 431462306a36Sopenharmony_ci return ice_sched_assoc_vsi_to_agg(pi, agg_info->agg_id, vsi_handle, 431562306a36Sopenharmony_ci replay_bitmap); 431662306a36Sopenharmony_ci} 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_ci/** 431962306a36Sopenharmony_ci * ice_replay_vsi_agg - replay VSI to aggregator node 432062306a36Sopenharmony_ci * @hw: pointer to the HW struct 432162306a36Sopenharmony_ci * @vsi_handle: software VSI handle 432262306a36Sopenharmony_ci * 432362306a36Sopenharmony_ci * This function replays association of VSI to aggregator type nodes, and 432462306a36Sopenharmony_ci * node bandwidth information. 432562306a36Sopenharmony_ci */ 432662306a36Sopenharmony_ciint ice_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle) 432762306a36Sopenharmony_ci{ 432862306a36Sopenharmony_ci struct ice_port_info *pi = hw->port_info; 432962306a36Sopenharmony_ci int status; 433062306a36Sopenharmony_ci 433162306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 433262306a36Sopenharmony_ci status = ice_sched_replay_vsi_agg(hw, vsi_handle); 433362306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 433462306a36Sopenharmony_ci return status; 433562306a36Sopenharmony_ci} 433662306a36Sopenharmony_ci 433762306a36Sopenharmony_ci/** 433862306a36Sopenharmony_ci * ice_sched_replay_q_bw - replay queue type node BW 433962306a36Sopenharmony_ci * @pi: port information structure 434062306a36Sopenharmony_ci * @q_ctx: queue context structure 434162306a36Sopenharmony_ci * 434262306a36Sopenharmony_ci * This function replays queue type node bandwidth. This function needs to be 434362306a36Sopenharmony_ci * called with scheduler lock held. 434462306a36Sopenharmony_ci */ 434562306a36Sopenharmony_ciint ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx) 434662306a36Sopenharmony_ci{ 434762306a36Sopenharmony_ci struct ice_sched_node *q_node; 434862306a36Sopenharmony_ci 434962306a36Sopenharmony_ci /* Following also checks the presence of node in tree */ 435062306a36Sopenharmony_ci q_node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid); 435162306a36Sopenharmony_ci if (!q_node) 435262306a36Sopenharmony_ci return -EINVAL; 435362306a36Sopenharmony_ci return ice_sched_replay_node_bw(pi->hw, q_node, &q_ctx->bw_t_info); 435462306a36Sopenharmony_ci} 4355