/** * ws_find_node - Find SC WS node based on VSI id or TC * @parent: parent node of First VSI or TC node * @match_val: value to match * @type: match type VSI/TC
*/ staticstruct irdma_ws_node *ws_find_node(struct irdma_ws_node *parent,
u16 match_val, enum irdma_ws_match_type type)
{ struct irdma_ws_node *node;
switch (type) { case WS_MATCH_TYPE_VSI:
list_for_each_entry(node, &parent->child_list_head, siblings) { if (node->vsi_index == match_val) return node;
} break; case WS_MATCH_TYPE_TC:
list_for_each_entry(node, &parent->child_list_head, siblings) { if (node->traffic_class == match_val) return node;
} break; default: break;
}
return NULL;
}
/** * irdma_tc_in_use - Checks to see if a leaf node is in use * @vsi: vsi pointer * @user_pri: user priority
*/ staticbool irdma_tc_in_use(struct irdma_sc_vsi *vsi, u8 user_pri)
{ int i;
mutex_lock(&vsi->qos[user_pri].qos_mutex); if (!list_empty(&vsi->qos[user_pri].qplist)) {
mutex_unlock(&vsi->qos[user_pri].qos_mutex); returntrue;
}
/* Check if the traffic class associated with the given user priority * is in use by any other user priority. If so, nothing left to do
*/ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) { if (vsi->qos[i].traffic_class == vsi->qos[user_pri].traffic_class &&
!list_empty(&vsi->qos[i].qplist)) {
mutex_unlock(&vsi->qos[user_pri].qos_mutex); returntrue;
}
}
mutex_unlock(&vsi->qos[user_pri].qos_mutex);
traffic_class = vsi->qos[user_pri].traffic_class; for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) if (vsi->qos[i].traffic_class == traffic_class)
vsi->qos[i].valid = false;
ws_tree_root = vsi->dev->ws_tree_root; if (!ws_tree_root) return;
vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
WS_MATCH_TYPE_VSI); if (!vsi_node) return;
tc_node = ws_find_node(vsi_node,
vsi->qos[user_pri].traffic_class,
WS_MATCH_TYPE_TC); if (!tc_node) return;
irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
vsi->unregister_qset(vsi, tc_node);
list_del(&tc_node->siblings);
irdma_free_node(vsi, tc_node); /* Check if VSI node can be freed */ if (list_empty(&vsi_node->child_list_head)) {
irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE);
list_del(&vsi_node->siblings);
irdma_free_node(vsi, vsi_node); /* Free head node there are no remaining VSI nodes */ if (list_empty(&ws_tree_root->child_list_head)) {
irdma_ws_cqp_cmd(vsi, ws_tree_root,
IRDMA_OP_WS_DELETE_NODE);
irdma_free_node(vsi, ws_tree_root);
vsi->dev->ws_tree_root = NULL;
}
}
}
/** * irdma_ws_add - Build work scheduler tree, set RDMA qs_handle * @vsi: vsi pointer * @user_pri: user priority
*/ int irdma_ws_add(struct irdma_sc_vsi *vsi, u8 user_pri)
{ struct irdma_ws_node *ws_tree_root; struct irdma_ws_node *vsi_node; struct irdma_ws_node *tc_node;
u16 traffic_class; int ret = 0; int i;
mutex_lock(&vsi->dev->ws_mutex); if (vsi->tc_change_pending) {
ret = -EBUSY; gotoexit;
}
if (vsi->qos[user_pri].valid) gotoexit;
ws_tree_root = vsi->dev->ws_tree_root; if (!ws_tree_root) {
ibdev_dbg(to_ibdev(vsi->dev), "WS: Creating root node\n");
ws_tree_root = irdma_alloc_node(vsi, user_pri,
WS_NODE_TYPE_PARENT, NULL); if (!ws_tree_root) {
ret = -ENOMEM; gotoexit;
}
ret = irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_ADD_NODE); if (ret) {
irdma_free_node(vsi, ws_tree_root); gotoexit;
}
vsi->dev->ws_tree_root = ws_tree_root;
}
/* Find a second tier node that matches the VSI */
vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
WS_MATCH_TYPE_VSI);
/* If VSI node doesn't exist, add one */ if (!vsi_node) {
ibdev_dbg(to_ibdev(vsi->dev), "WS: Node not found matching VSI %d\n",
vsi->vsi_idx);
vsi_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_PARENT,
ws_tree_root); if (!vsi_node) {
ret = -ENOMEM; goto vsi_add_err;
}
ret = irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_ADD_NODE); if (ret) {
irdma_free_node(vsi, vsi_node); goto vsi_add_err;
}
ibdev_dbg(to_ibdev(vsi->dev), "WS: Using node %d which represents VSI %d\n",
vsi_node->index, vsi->vsi_idx);
traffic_class = vsi->qos[user_pri].traffic_class;
tc_node = ws_find_node(vsi_node, traffic_class,
WS_MATCH_TYPE_TC); if (!tc_node) { /* Add leaf node */
ibdev_dbg(to_ibdev(vsi->dev), "WS: Node not found matching VSI %d and TC %d\n",
vsi->vsi_idx, traffic_class);
tc_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_LEAF,
vsi_node); if (!tc_node) {
ret = -ENOMEM; goto leaf_add_err;
}
ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_ADD_NODE); if (ret) {
irdma_free_node(vsi, tc_node); goto leaf_add_err;
}
list_add(&tc_node->siblings, &vsi_node->child_list_head); /* * callback to LAN to update the LAN tree with our node
*/
ret = vsi->register_qset(vsi, tc_node); if (ret) goto reg_err;
tc_node->enable = true;
ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_MODIFY_NODE); if (ret) {
vsi->unregister_qset(vsi, tc_node); goto reg_err;
}
}
ibdev_dbg(to_ibdev(vsi->dev), "WS: Using node %d which represents VSI %d TC %d\n",
tc_node->index, vsi->vsi_idx, traffic_class); /* * Iterate through other UPs and update the QS handle if they have * a matching traffic class.
*/ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) { if (vsi->qos[i].traffic_class == traffic_class) {
vsi->qos[i].qs_handle = tc_node->qs_handle;
vsi->qos[i].lan_qos_handle = tc_node->lan_qs_handle;
vsi->qos[i].l2_sched_node_id = tc_node->l2_sched_node_id;
vsi->qos[i].valid = true;
}
} gotoexit;
reg_err:
irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
list_del(&tc_node->siblings);
irdma_free_node(vsi, tc_node);
leaf_add_err: if (list_empty(&vsi_node->child_list_head)) { if (irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE)) gotoexit;
list_del(&vsi_node->siblings);
irdma_free_node(vsi, vsi_node);
}
vsi_add_err: /* Free head node there are no remaining VSI nodes */ if (list_empty(&ws_tree_root->child_list_head)) {
irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_DELETE_NODE);
vsi->dev->ws_tree_root = NULL;
irdma_free_node(vsi, ws_tree_root);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.