0001
0002
0003 #include "osdep.h"
0004 #include "hmc.h"
0005 #include "defs.h"
0006 #include "type.h"
0007 #include "protos.h"
0008
0009 #include "ws.h"
0010
0011
0012
0013
0014
0015
0016
0017
0018 static struct irdma_ws_node *irdma_alloc_node(struct irdma_sc_vsi *vsi,
0019 u8 user_pri,
0020 enum irdma_ws_node_type node_type,
0021 struct irdma_ws_node *parent)
0022 {
0023 struct irdma_virt_mem ws_mem;
0024 struct irdma_ws_node *node;
0025 u16 node_index = 0;
0026
0027 ws_mem.size = sizeof(struct irdma_ws_node);
0028 ws_mem.va = kzalloc(ws_mem.size, GFP_KERNEL);
0029 if (!ws_mem.va)
0030 return NULL;
0031
0032 if (parent) {
0033 node_index = irdma_alloc_ws_node_id(vsi->dev);
0034 if (node_index == IRDMA_WS_NODE_INVALID) {
0035 kfree(ws_mem.va);
0036 return NULL;
0037 }
0038 }
0039
0040 node = ws_mem.va;
0041 node->index = node_index;
0042 node->vsi_index = vsi->vsi_idx;
0043 INIT_LIST_HEAD(&node->child_list_head);
0044 if (node_type == WS_NODE_TYPE_LEAF) {
0045 node->type_leaf = true;
0046 node->traffic_class = vsi->qos[user_pri].traffic_class;
0047 node->user_pri = user_pri;
0048 node->rel_bw = vsi->qos[user_pri].rel_bw;
0049 if (!node->rel_bw)
0050 node->rel_bw = 1;
0051
0052 node->lan_qs_handle = vsi->qos[user_pri].lan_qos_handle;
0053 node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
0054 } else {
0055 node->rel_bw = 1;
0056 node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
0057 node->enable = true;
0058 }
0059
0060 node->parent = parent;
0061
0062 return node;
0063 }
0064
0065
0066
0067
0068
0069
0070 static void irdma_free_node(struct irdma_sc_vsi *vsi,
0071 struct irdma_ws_node *node)
0072 {
0073 struct irdma_virt_mem ws_mem;
0074
0075 if (node->index)
0076 irdma_free_ws_node_id(vsi->dev, node->index);
0077
0078 ws_mem.va = node;
0079 ws_mem.size = sizeof(struct irdma_ws_node);
0080 kfree(ws_mem.va);
0081 }
0082
0083
0084
0085
0086
0087
0088
0089 static int irdma_ws_cqp_cmd(struct irdma_sc_vsi *vsi,
0090 struct irdma_ws_node *node, u8 cmd)
0091 {
0092 struct irdma_ws_node_info node_info = {};
0093
0094 node_info.id = node->index;
0095 node_info.vsi = node->vsi_index;
0096 if (node->parent)
0097 node_info.parent_id = node->parent->index;
0098 else
0099 node_info.parent_id = node_info.id;
0100
0101 node_info.weight = node->rel_bw;
0102 node_info.tc = node->traffic_class;
0103 node_info.prio_type = node->prio_type;
0104 node_info.type_leaf = node->type_leaf;
0105 node_info.enable = node->enable;
0106 if (irdma_cqp_ws_node_cmd(vsi->dev, cmd, &node_info)) {
0107 ibdev_dbg(to_ibdev(vsi->dev), "WS: CQP WS CMD failed\n");
0108 return -ENOMEM;
0109 }
0110
0111 if (node->type_leaf && cmd == IRDMA_OP_WS_ADD_NODE) {
0112 node->qs_handle = node_info.qs_handle;
0113 vsi->qos[node->user_pri].qs_handle = node_info.qs_handle;
0114 }
0115
0116 return 0;
0117 }
0118
0119
0120
0121
0122
0123
0124
0125 static struct irdma_ws_node *ws_find_node(struct irdma_ws_node *parent,
0126 u16 match_val,
0127 enum irdma_ws_match_type type)
0128 {
0129 struct irdma_ws_node *node;
0130
0131 switch (type) {
0132 case WS_MATCH_TYPE_VSI:
0133 list_for_each_entry(node, &parent->child_list_head, siblings) {
0134 if (node->vsi_index == match_val)
0135 return node;
0136 }
0137 break;
0138 case WS_MATCH_TYPE_TC:
0139 list_for_each_entry(node, &parent->child_list_head, siblings) {
0140 if (node->traffic_class == match_val)
0141 return node;
0142 }
0143 break;
0144 default:
0145 break;
0146 }
0147
0148 return NULL;
0149 }
0150
0151
0152
0153
0154
0155
0156 static bool irdma_tc_in_use(struct irdma_sc_vsi *vsi, u8 user_pri)
0157 {
0158 int i;
0159
0160 mutex_lock(&vsi->qos[user_pri].qos_mutex);
0161 if (!list_empty(&vsi->qos[user_pri].qplist)) {
0162 mutex_unlock(&vsi->qos[user_pri].qos_mutex);
0163 return true;
0164 }
0165
0166
0167
0168
0169 for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
0170 if (vsi->qos[i].traffic_class == vsi->qos[user_pri].traffic_class &&
0171 !list_empty(&vsi->qos[i].qplist)) {
0172 mutex_unlock(&vsi->qos[user_pri].qos_mutex);
0173 return true;
0174 }
0175 }
0176 mutex_unlock(&vsi->qos[user_pri].qos_mutex);
0177
0178 return false;
0179 }
0180
0181
0182
0183
0184
0185
0186 static void irdma_remove_leaf(struct irdma_sc_vsi *vsi, u8 user_pri)
0187 {
0188 struct irdma_ws_node *ws_tree_root, *vsi_node, *tc_node;
0189 int i;
0190 u16 traffic_class;
0191
0192 traffic_class = vsi->qos[user_pri].traffic_class;
0193 for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++)
0194 if (vsi->qos[i].traffic_class == traffic_class)
0195 vsi->qos[i].valid = false;
0196
0197 ws_tree_root = vsi->dev->ws_tree_root;
0198 if (!ws_tree_root)
0199 return;
0200
0201 vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
0202 WS_MATCH_TYPE_VSI);
0203 if (!vsi_node)
0204 return;
0205
0206 tc_node = ws_find_node(vsi_node,
0207 vsi->qos[user_pri].traffic_class,
0208 WS_MATCH_TYPE_TC);
0209 if (!tc_node)
0210 return;
0211
0212 irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
0213 vsi->unregister_qset(vsi, tc_node);
0214 list_del(&tc_node->siblings);
0215 irdma_free_node(vsi, tc_node);
0216
0217 if (list_empty(&vsi_node->child_list_head)) {
0218 irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE);
0219 list_del(&vsi_node->siblings);
0220 irdma_free_node(vsi, vsi_node);
0221
0222 if (list_empty(&ws_tree_root->child_list_head)) {
0223 irdma_ws_cqp_cmd(vsi, ws_tree_root,
0224 IRDMA_OP_WS_DELETE_NODE);
0225 irdma_free_node(vsi, ws_tree_root);
0226 vsi->dev->ws_tree_root = NULL;
0227 }
0228 }
0229 }
0230
0231
0232
0233
0234
0235
0236 int irdma_ws_add(struct irdma_sc_vsi *vsi, u8 user_pri)
0237 {
0238 struct irdma_ws_node *ws_tree_root;
0239 struct irdma_ws_node *vsi_node;
0240 struct irdma_ws_node *tc_node;
0241 u16 traffic_class;
0242 int ret = 0;
0243 int i;
0244
0245 mutex_lock(&vsi->dev->ws_mutex);
0246 if (vsi->tc_change_pending) {
0247 ret = -EBUSY;
0248 goto exit;
0249 }
0250
0251 if (vsi->qos[user_pri].valid)
0252 goto exit;
0253
0254 ws_tree_root = vsi->dev->ws_tree_root;
0255 if (!ws_tree_root) {
0256 ibdev_dbg(to_ibdev(vsi->dev), "WS: Creating root node\n");
0257 ws_tree_root = irdma_alloc_node(vsi, user_pri,
0258 WS_NODE_TYPE_PARENT, NULL);
0259 if (!ws_tree_root) {
0260 ret = -ENOMEM;
0261 goto exit;
0262 }
0263
0264 ret = irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_ADD_NODE);
0265 if (ret) {
0266 irdma_free_node(vsi, ws_tree_root);
0267 goto exit;
0268 }
0269
0270 vsi->dev->ws_tree_root = ws_tree_root;
0271 }
0272
0273
0274 vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
0275 WS_MATCH_TYPE_VSI);
0276
0277
0278 if (!vsi_node) {
0279 ibdev_dbg(to_ibdev(vsi->dev),
0280 "WS: Node not found matching VSI %d\n",
0281 vsi->vsi_idx);
0282 vsi_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_PARENT,
0283 ws_tree_root);
0284 if (!vsi_node) {
0285 ret = -ENOMEM;
0286 goto vsi_add_err;
0287 }
0288
0289 ret = irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_ADD_NODE);
0290 if (ret) {
0291 irdma_free_node(vsi, vsi_node);
0292 goto vsi_add_err;
0293 }
0294
0295 list_add(&vsi_node->siblings, &ws_tree_root->child_list_head);
0296 }
0297
0298 ibdev_dbg(to_ibdev(vsi->dev),
0299 "WS: Using node %d which represents VSI %d\n",
0300 vsi_node->index, vsi->vsi_idx);
0301 traffic_class = vsi->qos[user_pri].traffic_class;
0302 tc_node = ws_find_node(vsi_node, traffic_class,
0303 WS_MATCH_TYPE_TC);
0304 if (!tc_node) {
0305
0306 ibdev_dbg(to_ibdev(vsi->dev),
0307 "WS: Node not found matching VSI %d and TC %d\n",
0308 vsi->vsi_idx, traffic_class);
0309 tc_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_LEAF,
0310 vsi_node);
0311 if (!tc_node) {
0312 ret = -ENOMEM;
0313 goto leaf_add_err;
0314 }
0315
0316 ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_ADD_NODE);
0317 if (ret) {
0318 irdma_free_node(vsi, tc_node);
0319 goto leaf_add_err;
0320 }
0321
0322 list_add(&tc_node->siblings, &vsi_node->child_list_head);
0323
0324
0325
0326 ret = vsi->register_qset(vsi, tc_node);
0327 if (ret)
0328 goto reg_err;
0329
0330 tc_node->enable = true;
0331 ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_MODIFY_NODE);
0332 if (ret) {
0333 vsi->unregister_qset(vsi, tc_node);
0334 goto reg_err;
0335 }
0336 }
0337 ibdev_dbg(to_ibdev(vsi->dev),
0338 "WS: Using node %d which represents VSI %d TC %d\n",
0339 tc_node->index, vsi->vsi_idx, traffic_class);
0340
0341
0342
0343
0344 for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
0345 if (vsi->qos[i].traffic_class == traffic_class) {
0346 vsi->qos[i].qs_handle = tc_node->qs_handle;
0347 vsi->qos[i].lan_qos_handle = tc_node->lan_qs_handle;
0348 vsi->qos[i].l2_sched_node_id = tc_node->l2_sched_node_id;
0349 vsi->qos[i].valid = true;
0350 }
0351 }
0352 goto exit;
0353
0354 reg_err:
0355 irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
0356 list_del(&tc_node->siblings);
0357 irdma_free_node(vsi, tc_node);
0358 leaf_add_err:
0359 if (list_empty(&vsi_node->child_list_head)) {
0360 if (irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE))
0361 goto exit;
0362 list_del(&vsi_node->siblings);
0363 irdma_free_node(vsi, vsi_node);
0364 }
0365
0366 vsi_add_err:
0367
0368 if (list_empty(&ws_tree_root->child_list_head)) {
0369 irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_DELETE_NODE);
0370 vsi->dev->ws_tree_root = NULL;
0371 irdma_free_node(vsi, ws_tree_root);
0372 }
0373
0374 exit:
0375 mutex_unlock(&vsi->dev->ws_mutex);
0376 return ret;
0377 }
0378
0379
0380
0381
0382
0383
0384 void irdma_ws_remove(struct irdma_sc_vsi *vsi, u8 user_pri)
0385 {
0386 mutex_lock(&vsi->dev->ws_mutex);
0387 if (irdma_tc_in_use(vsi, user_pri))
0388 goto exit;
0389 irdma_remove_leaf(vsi, user_pri);
0390 exit:
0391 mutex_unlock(&vsi->dev->ws_mutex);
0392 }
0393
0394
0395
0396
0397
0398 void irdma_ws_reset(struct irdma_sc_vsi *vsi)
0399 {
0400 u8 i;
0401
0402 mutex_lock(&vsi->dev->ws_mutex);
0403 for (i = 0; i < IRDMA_MAX_USER_PRIORITY; ++i)
0404 irdma_remove_leaf(vsi, i);
0405 mutex_unlock(&vsi->dev->ws_mutex);
0406 }