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