xref: /freebsd/sys/dev/irdma/irdma_ws.c (revision 5b5f7d0e)
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 
605b5f7d0eSBartosz 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;
1125b5f7d0eSBartosz 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