The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/irdma/irdma_ws.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
    3  *
    4  * Copyright (c) 2017 - 2022 Intel Corporation
    5  *
    6  * This software is available to you under a choice of one of two
    7  * licenses.  You may choose to be licensed under the terms of the GNU
    8  * General Public License (GPL) Version 2, available from the file
    9  * COPYING in the main directory of this source tree, or the
   10  * OpenFabrics.org BSD license below:
   11  *
   12  *   Redistribution and use in source and binary forms, with or
   13  *   without modification, are permitted provided that the following
   14  *   conditions are met:
   15  *
   16  *    - Redistributions of source code must retain the above
   17  *      copyright notice, this list of conditions and the following
   18  *      disclaimer.
   19  *
   20  *    - Redistributions in binary form must reproduce the above
   21  *      copyright notice, this list of conditions and the following
   22  *      disclaimer in the documentation and/or other materials
   23  *      provided with the distribution.
   24  *
   25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   32  * SOFTWARE.
   33  */
   34 /*$FreeBSD$*/
   35 
   36 #include "osdep.h"
   37 #include "irdma_hmc.h"
   38 #include "irdma_defs.h"
   39 #include "irdma_type.h"
   40 #include "irdma_protos.h"
   41 
   42 #include "irdma_ws.h"
   43 
   44 /**
   45  * irdma_alloc_node - Allocate a WS node and init
   46  * @vsi: vsi pointer
   47  * @user_pri: user priority
   48  * @node_type: Type of node, leaf or parent
   49  * @parent: parent node pointer
   50  */
   51 static struct irdma_ws_node *
   52 irdma_alloc_node(struct irdma_sc_vsi *vsi,
   53                  u8 user_pri,
   54                  enum irdma_ws_node_type node_type,
   55                  struct irdma_ws_node *parent)
   56 {
   57         struct irdma_virt_mem ws_mem;
   58         struct irdma_ws_node *node;
   59         u16 node_index = 0;
   60 
   61         ws_mem.size = sizeof(struct irdma_ws_node);
   62         ws_mem.va = kzalloc(ws_mem.size, GFP_KERNEL);
   63         if (!ws_mem.va)
   64                 return NULL;
   65 
   66         if (parent) {
   67                 node_index = irdma_alloc_ws_node_id(vsi->dev);
   68                 if (node_index == IRDMA_WS_NODE_INVALID) {
   69                         kfree(ws_mem.va);
   70                         return NULL;
   71                 }
   72         }
   73 
   74         node = ws_mem.va;
   75         node->index = node_index;
   76         node->vsi_index = vsi->vsi_idx;
   77         INIT_LIST_HEAD(&node->child_list_head);
   78         if (node_type == WS_NODE_TYPE_LEAF) {
   79                 node->type_leaf = true;
   80                 node->traffic_class = vsi->qos[user_pri].traffic_class;
   81                 node->user_pri = user_pri;
   82                 node->rel_bw = vsi->qos[user_pri].rel_bw;
   83                 if (!node->rel_bw)
   84                         node->rel_bw = 1;
   85 
   86                 node->lan_qs_handle = vsi->qos[user_pri].lan_qos_handle;
   87                 node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
   88         } else {
   89                 node->rel_bw = 1;
   90                 node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
   91                 node->enable = true;
   92         }
   93 
   94         node->parent = parent;
   95 
   96         return node;
   97 }
   98 
   99 /**
  100  * irdma_free_node - Free a WS node
  101  * @vsi: VSI stricture of device
  102  * @node: Pointer to node to free
  103  */
  104 static void
  105 irdma_free_node(struct irdma_sc_vsi *vsi,
  106                 struct irdma_ws_node *node)
  107 {
  108         struct irdma_virt_mem ws_mem;
  109 
  110         if (node->index)
  111                 irdma_free_ws_node_id(vsi->dev, node->index);
  112 
  113         ws_mem.va = node;
  114         ws_mem.size = sizeof(struct irdma_ws_node);
  115         kfree(ws_mem.va);
  116 }
  117 
  118 /**
  119  * irdma_ws_cqp_cmd - Post CQP work scheduler node cmd
  120  * @vsi: vsi pointer
  121  * @node: pointer to node
  122  * @cmd: add, remove or modify
  123  */
  124 static int
  125 irdma_ws_cqp_cmd(struct irdma_sc_vsi *vsi,
  126                  struct irdma_ws_node *node, u8 cmd)
  127 {
  128         struct irdma_ws_node_info node_info = {0};
  129 
  130         node_info.id = node->index;
  131         node_info.vsi = node->vsi_index;
  132         if (node->parent)
  133                 node_info.parent_id = node->parent->index;
  134         else
  135                 node_info.parent_id = node_info.id;
  136 
  137         node_info.weight = node->rel_bw;
  138         node_info.tc = node->traffic_class;
  139         node_info.prio_type = node->prio_type;
  140         node_info.type_leaf = node->type_leaf;
  141         node_info.enable = node->enable;
  142         if (irdma_cqp_ws_node_cmd(vsi->dev, cmd, &node_info)) {
  143                 irdma_debug(vsi->dev, IRDMA_DEBUG_WS, "CQP WS CMD failed\n");
  144                 return -ENOMEM;
  145         }
  146 
  147         if (node->type_leaf && cmd == IRDMA_OP_WS_ADD_NODE) {
  148                 node->qs_handle = node_info.qs_handle;
  149                 vsi->qos[node->user_pri].qs_handle = node_info.qs_handle;
  150         }
  151 
  152         return 0;
  153 }
  154 
  155 /**
  156  * ws_find_node - Find SC WS node based on VSI id or TC
  157  * @parent: parent node of First VSI or TC node
  158  * @match_val: value to match
  159  * @type: match type VSI/TC
  160  */
  161 static struct irdma_ws_node *
  162 ws_find_node(struct irdma_ws_node *parent,
  163              u16 match_val,
  164              enum irdma_ws_match_type type)
  165 {
  166         struct irdma_ws_node *node;
  167 
  168         switch (type) {
  169         case WS_MATCH_TYPE_VSI:
  170                 list_for_each_entry(node, &parent->child_list_head, siblings) {
  171                         if (node->vsi_index == match_val)
  172                                 return node;
  173                 }
  174                 break;
  175         case WS_MATCH_TYPE_TC:
  176                 list_for_each_entry(node, &parent->child_list_head, siblings) {
  177                         if (node->traffic_class == match_val)
  178                                 return node;
  179                 }
  180                 break;
  181         default:
  182                 break;
  183         }
  184 
  185         return NULL;
  186 }
  187 
  188 /**
  189  * irdma_ws_in_use - Checks to see if a leaf node is in use
  190  * @vsi: vsi pointer
  191  * @user_pri: user priority
  192  */
  193 static bool
  194 irdma_ws_in_use(struct irdma_sc_vsi *vsi, u8 user_pri)
  195 {
  196         int i;
  197 
  198         mutex_lock(&vsi->qos[user_pri].qos_mutex);
  199         if (!list_empty(&vsi->qos[user_pri].qplist)) {
  200                 mutex_unlock(&vsi->qos[user_pri].qos_mutex);
  201                 return true;
  202         }
  203 
  204         /*
  205          * Check if the qs handle associated with the given user priority is in use by any other user priority. If so,
  206          * nothing left to do
  207          */
  208         for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
  209                 if (vsi->qos[i].qs_handle == vsi->qos[user_pri].qs_handle &&
  210                     !list_empty(&vsi->qos[i].qplist)) {
  211                         mutex_unlock(&vsi->qos[user_pri].qos_mutex);
  212                         return true;
  213                 }
  214         }
  215         mutex_unlock(&vsi->qos[user_pri].qos_mutex);
  216 
  217         return false;
  218 }
  219 
  220 /**
  221  * irdma_remove_leaf - Remove leaf node unconditionally
  222  * @vsi: vsi pointer
  223  * @user_pri: user priority
  224  */
  225 static void
  226 irdma_remove_leaf(struct irdma_sc_vsi *vsi, u8 user_pri)
  227 {
  228         struct irdma_ws_node *ws_tree_root, *vsi_node, *tc_node;
  229         u16 qs_handle;
  230         int i;
  231 
  232         qs_handle = vsi->qos[user_pri].qs_handle;
  233         for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++)
  234                 if (vsi->qos[i].qs_handle == qs_handle)
  235                         vsi->qos[i].valid = false;
  236 
  237         ws_tree_root = vsi->dev->ws_tree_root;
  238         if (!ws_tree_root)
  239                 return;
  240 
  241         vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
  242                                 WS_MATCH_TYPE_VSI);
  243         if (!vsi_node)
  244                 return;
  245 
  246         tc_node = ws_find_node(vsi_node,
  247                                vsi->qos[user_pri].traffic_class,
  248                                WS_MATCH_TYPE_TC);
  249         if (!tc_node)
  250                 return;
  251 
  252         irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
  253         vsi->unregister_qset(vsi, tc_node);
  254         list_del(&tc_node->siblings);
  255         irdma_free_node(vsi, tc_node);
  256         /* Check if VSI node can be freed */
  257         if (list_empty(&vsi_node->child_list_head)) {
  258                 irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE);
  259                 list_del(&vsi_node->siblings);
  260                 irdma_free_node(vsi, vsi_node);
  261                 /* Free head node there are no remaining VSI nodes */
  262                 if (list_empty(&ws_tree_root->child_list_head)) {
  263                         irdma_ws_cqp_cmd(vsi, ws_tree_root,
  264                                          IRDMA_OP_WS_DELETE_NODE);
  265                         irdma_free_node(vsi, ws_tree_root);
  266                         vsi->dev->ws_tree_root = NULL;
  267                 }
  268         }
  269 }
  270 
  271 /**
  272  * irdma_ws_add - Build work scheduler tree, set RDMA qs_handle
  273  * @vsi: vsi pointer
  274  * @user_pri: user priority
  275  */
  276 int
  277 irdma_ws_add(struct irdma_sc_vsi *vsi, u8 user_pri)
  278 {
  279         struct irdma_ws_node *ws_tree_root;
  280         struct irdma_ws_node *vsi_node;
  281         struct irdma_ws_node *tc_node;
  282         u16 traffic_class;
  283         int ret = 0;
  284         int i;
  285 
  286         mutex_lock(&vsi->dev->ws_mutex);
  287         if (vsi->tc_change_pending) {
  288                 ret = -EBUSY;
  289                 goto exit;
  290         }
  291 
  292         if (vsi->qos[user_pri].valid)
  293                 goto exit;
  294 
  295         ws_tree_root = vsi->dev->ws_tree_root;
  296         if (!ws_tree_root) {
  297                 irdma_debug(vsi->dev, IRDMA_DEBUG_WS, "Creating root node\n");
  298                 ws_tree_root = irdma_alloc_node(vsi, user_pri,
  299                                                 WS_NODE_TYPE_PARENT, NULL);
  300                 if (!ws_tree_root) {
  301                         ret = -ENOMEM;
  302                         goto exit;
  303                 }
  304 
  305                 ret = irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_ADD_NODE);
  306                 if (ret) {
  307                         irdma_free_node(vsi, ws_tree_root);
  308                         goto exit;
  309                 }
  310 
  311                 vsi->dev->ws_tree_root = ws_tree_root;
  312         }
  313 
  314         /* Find a second tier node that matches the VSI */
  315         vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
  316                                 WS_MATCH_TYPE_VSI);
  317 
  318         /* If VSI node doesn't exist, add one */
  319         if (!vsi_node) {
  320                 irdma_debug(vsi->dev, IRDMA_DEBUG_WS,
  321                             "Node not found matching VSI %d\n", vsi->vsi_idx);
  322                 vsi_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_PARENT,
  323                                             ws_tree_root);
  324                 if (!vsi_node) {
  325                         ret = -ENOMEM;
  326                         goto vsi_add_err;
  327                 }
  328 
  329                 ret = irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_ADD_NODE);
  330                 if (ret) {
  331                         irdma_free_node(vsi, vsi_node);
  332                         goto vsi_add_err;
  333                 }
  334 
  335                 list_add(&vsi_node->siblings, &ws_tree_root->child_list_head);
  336         }
  337 
  338         irdma_debug(vsi->dev, IRDMA_DEBUG_WS,
  339                     "Using node %d which represents VSI %d\n", vsi_node->index,
  340                     vsi->vsi_idx);
  341         traffic_class = vsi->qos[user_pri].traffic_class;
  342         tc_node = ws_find_node(vsi_node, traffic_class,
  343                                WS_MATCH_TYPE_TC);
  344         if (!tc_node) {
  345                 /* Add leaf node */
  346                 irdma_debug(vsi->dev, IRDMA_DEBUG_WS,
  347                             "Node not found matching VSI %d and TC %d\n",
  348                             vsi->vsi_idx, traffic_class);
  349                 tc_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_LEAF,
  350                                            vsi_node);
  351                 if (!tc_node) {
  352                         ret = -ENOMEM;
  353                         goto leaf_add_err;
  354                 }
  355 
  356                 ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_ADD_NODE);
  357                 if (ret) {
  358                         irdma_free_node(vsi, tc_node);
  359                         goto leaf_add_err;
  360                 }
  361 
  362                 list_add(&tc_node->siblings, &vsi_node->child_list_head);
  363                 /*
  364                  * callback to LAN to update the LAN tree with our node
  365                  */
  366                 ret = vsi->register_qset(vsi, tc_node);
  367                 if (ret)
  368                         goto reg_err;
  369 
  370                 tc_node->enable = true;
  371                 ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_MODIFY_NODE);
  372                 if (ret) {
  373                         vsi->unregister_qset(vsi, tc_node);
  374                         goto reg_err;
  375                 }
  376         }
  377         irdma_debug(vsi->dev, IRDMA_DEBUG_WS,
  378                     "Using node %d which represents VSI %d TC %d\n",
  379                     tc_node->index, vsi->vsi_idx, traffic_class);
  380         /*
  381          * Iterate through other UPs and update the QS handle if they have a matching traffic class.
  382          */
  383         for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
  384                 if (vsi->qos[i].traffic_class == traffic_class) {
  385                         vsi->qos[i].qs_handle = tc_node->qs_handle;
  386                         vsi->qos[i].lan_qos_handle = tc_node->lan_qs_handle;
  387                         vsi->qos[i].l2_sched_node_id = tc_node->l2_sched_node_id;
  388                         vsi->qos[i].valid = true;
  389                 }
  390         }
  391         goto exit;
  392 
  393 reg_err:
  394         irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
  395         list_del(&tc_node->siblings);
  396         irdma_free_node(vsi, tc_node);
  397 leaf_add_err:
  398         if (list_empty(&vsi_node->child_list_head)) {
  399                 if (irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE))
  400                         goto exit;
  401                 list_del(&vsi_node->siblings);
  402                 irdma_free_node(vsi, vsi_node);
  403         }
  404 
  405 vsi_add_err:
  406         /* Free head node there are no remaining VSI nodes */
  407         if (list_empty(&ws_tree_root->child_list_head)) {
  408                 irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_DELETE_NODE);
  409                 vsi->dev->ws_tree_root = NULL;
  410                 irdma_free_node(vsi, ws_tree_root);
  411         }
  412 
  413 exit:
  414         mutex_unlock(&vsi->dev->ws_mutex);
  415         return ret;
  416 }
  417 
  418 /**
  419  * irdma_ws_remove - Free WS scheduler node, update WS tree
  420  * @vsi: vsi pointer
  421  * @user_pri: user priority
  422  */
  423 void
  424 irdma_ws_remove(struct irdma_sc_vsi *vsi, u8 user_pri)
  425 {
  426         mutex_lock(&vsi->dev->ws_mutex);
  427         if (irdma_ws_in_use(vsi, user_pri))
  428                 goto exit;
  429         irdma_remove_leaf(vsi, user_pri);
  430 exit:
  431         mutex_unlock(&vsi->dev->ws_mutex);
  432 }
  433 
  434 /**
  435  * irdma_ws_reset - Reset entire WS tree
  436  * @vsi: vsi pointer
  437  */
  438 void
  439 irdma_ws_reset(struct irdma_sc_vsi *vsi)
  440 {
  441         u8 i;
  442 
  443         mutex_lock(&vsi->dev->ws_mutex);
  444         for (i = 0; i < IRDMA_MAX_USER_PRIORITY; ++i)
  445                 irdma_remove_leaf(vsi, i);
  446         mutex_unlock(&vsi->dev->ws_mutex);
  447 }

Cache object: 72dac366b6d4ea59c25d9fa2dc535448


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.