Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/* Copyright (c) 2017 - 2021 Intel Corporation */
  3#include "osdep.h"
 
  4#include "hmc.h"
  5#include "defs.h"
  6#include "type.h"
  7#include "protos.h"
  8
  9#include "ws.h"
 10
 11/**
 12 * irdma_alloc_node - Allocate a WS node and init
 13 * @vsi: vsi pointer
 14 * @user_pri: user priority
 15 * @node_type: Type of node, leaf or parent
 16 * @parent: parent node pointer
 17 */
 18static struct irdma_ws_node *irdma_alloc_node(struct irdma_sc_vsi *vsi,
 19					      u8 user_pri,
 20					      enum irdma_ws_node_type node_type,
 21					      struct irdma_ws_node *parent)
 22{
 23	struct irdma_virt_mem ws_mem;
 24	struct irdma_ws_node *node;
 25	u16 node_index = 0;
 26
 27	ws_mem.size = sizeof(struct irdma_ws_node);
 28	ws_mem.va = kzalloc(ws_mem.size, GFP_KERNEL);
 29	if (!ws_mem.va)
 30		return NULL;
 31
 32	if (parent) {
 33		node_index = irdma_alloc_ws_node_id(vsi->dev);
 34		if (node_index == IRDMA_WS_NODE_INVALID) {
 35			kfree(ws_mem.va);
 36			return NULL;
 37		}
 38	}
 39
 40	node = ws_mem.va;
 41	node->index = node_index;
 42	node->vsi_index = vsi->vsi_idx;
 43	INIT_LIST_HEAD(&node->child_list_head);
 44	if (node_type == WS_NODE_TYPE_LEAF) {
 45		node->type_leaf = true;
 46		node->traffic_class = vsi->qos[user_pri].traffic_class;
 47		node->user_pri = user_pri;
 48		node->rel_bw = vsi->qos[user_pri].rel_bw;
 49		if (!node->rel_bw)
 50			node->rel_bw = 1;
 51
 52		node->lan_qs_handle = vsi->qos[user_pri].lan_qos_handle;
 53		node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
 54	} else {
 55		node->rel_bw = 1;
 56		node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
 57		node->enable = true;
 58	}
 59
 60	node->parent = parent;
 61
 62	return node;
 63}
 64
 65/**
 66 * irdma_free_node - Free a WS node
 67 * @vsi: VSI stricture of device
 68 * @node: Pointer to node to free
 69 */
 70static void irdma_free_node(struct irdma_sc_vsi *vsi,
 71			    struct irdma_ws_node *node)
 72{
 73	struct irdma_virt_mem ws_mem;
 74
 75	if (node->index)
 76		irdma_free_ws_node_id(vsi->dev, node->index);
 77
 78	ws_mem.va = node;
 79	ws_mem.size = sizeof(struct irdma_ws_node);
 80	kfree(ws_mem.va);
 81}
 82
 83/**
 84 * irdma_ws_cqp_cmd - Post CQP work scheduler node cmd
 85 * @vsi: vsi pointer
 86 * @node: pointer to node
 87 * @cmd: add, remove or modify
 88 */
 89static int irdma_ws_cqp_cmd(struct irdma_sc_vsi *vsi,
 90			    struct irdma_ws_node *node, u8 cmd)
 91{
 92	struct irdma_ws_node_info node_info = {};
 93
 94	node_info.id = node->index;
 95	node_info.vsi = node->vsi_index;
 96	if (node->parent)
 97		node_info.parent_id = node->parent->index;
 98	else
 99		node_info.parent_id = node_info.id;
100
101	node_info.weight = node->rel_bw;
102	node_info.tc = node->traffic_class;
103	node_info.prio_type = node->prio_type;
104	node_info.type_leaf = node->type_leaf;
105	node_info.enable = node->enable;
106	if (irdma_cqp_ws_node_cmd(vsi->dev, cmd, &node_info)) {
107		ibdev_dbg(to_ibdev(vsi->dev), "WS: CQP WS CMD failed\n");
108		return -ENOMEM;
109	}
110
111	if (node->type_leaf && cmd == IRDMA_OP_WS_ADD_NODE) {
112		node->qs_handle = node_info.qs_handle;
113		vsi->qos[node->user_pri].qs_handle = node_info.qs_handle;
114	}
115
116	return 0;
117}
118
119/**
120 * ws_find_node - Find SC WS node based on VSI id or TC
121 * @parent: parent node of First VSI or TC node
122 * @match_val: value to match
123 * @type: match type VSI/TC
124 */
125static struct irdma_ws_node *ws_find_node(struct irdma_ws_node *parent,
126					  u16 match_val,
127					  enum irdma_ws_match_type type)
128{
129	struct irdma_ws_node *node;
130
131	switch (type) {
132	case WS_MATCH_TYPE_VSI:
133		list_for_each_entry(node, &parent->child_list_head, siblings) {
134			if (node->vsi_index == match_val)
135				return node;
136		}
137		break;
138	case WS_MATCH_TYPE_TC:
139		list_for_each_entry(node, &parent->child_list_head, siblings) {
140			if (node->traffic_class == match_val)
141				return node;
142		}
143		break;
144	default:
145		break;
146	}
147
148	return NULL;
149}
150
151/**
152 * irdma_tc_in_use - Checks to see if a leaf node is in use
153 * @vsi: vsi pointer
154 * @user_pri: user priority
155 */
156static bool irdma_tc_in_use(struct irdma_sc_vsi *vsi, u8 user_pri)
157{
158	int i;
159
160	mutex_lock(&vsi->qos[user_pri].qos_mutex);
161	if (!list_empty(&vsi->qos[user_pri].qplist)) {
162		mutex_unlock(&vsi->qos[user_pri].qos_mutex);
163		return true;
164	}
165
166	/* Check if the traffic class associated with the given user priority
167	 * is in use by any other user priority. If so, nothing left to do
168	 */
169	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
170		if (vsi->qos[i].traffic_class == vsi->qos[user_pri].traffic_class &&
171		    !list_empty(&vsi->qos[i].qplist)) {
172			mutex_unlock(&vsi->qos[user_pri].qos_mutex);
173			return true;
174		}
175	}
176	mutex_unlock(&vsi->qos[user_pri].qos_mutex);
177
178	return false;
179}
180
181/**
182 * irdma_remove_leaf - Remove leaf node unconditionally
183 * @vsi: vsi pointer
184 * @user_pri: user priority
185 */
186static void irdma_remove_leaf(struct irdma_sc_vsi *vsi, u8 user_pri)
187{
188	struct irdma_ws_node *ws_tree_root, *vsi_node, *tc_node;
189	int i;
190	u16 traffic_class;
191
192	traffic_class = vsi->qos[user_pri].traffic_class;
193	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++)
194		if (vsi->qos[i].traffic_class == traffic_class)
195			vsi->qos[i].valid = false;
196
197	ws_tree_root = vsi->dev->ws_tree_root;
198	if (!ws_tree_root)
199		return;
200
201	vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
202				WS_MATCH_TYPE_VSI);
203	if (!vsi_node)
204		return;
205
206	tc_node = ws_find_node(vsi_node,
207			       vsi->qos[user_pri].traffic_class,
208			       WS_MATCH_TYPE_TC);
209	if (!tc_node)
210		return;
211
212	irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
213	vsi->unregister_qset(vsi, tc_node);
214	list_del(&tc_node->siblings);
215	irdma_free_node(vsi, tc_node);
216	/* Check if VSI node can be freed */
217	if (list_empty(&vsi_node->child_list_head)) {
218		irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE);
219		list_del(&vsi_node->siblings);
220		irdma_free_node(vsi, vsi_node);
221		/* Free head node there are no remaining VSI nodes */
222		if (list_empty(&ws_tree_root->child_list_head)) {
223			irdma_ws_cqp_cmd(vsi, ws_tree_root,
224					 IRDMA_OP_WS_DELETE_NODE);
225			irdma_free_node(vsi, ws_tree_root);
226			vsi->dev->ws_tree_root = NULL;
227		}
228	}
229}
230
231/**
232 * irdma_ws_add - Build work scheduler tree, set RDMA qs_handle
233 * @vsi: vsi pointer
234 * @user_pri: user priority
235 */
236int irdma_ws_add(struct irdma_sc_vsi *vsi, u8 user_pri)
237{
238	struct irdma_ws_node *ws_tree_root;
239	struct irdma_ws_node *vsi_node;
240	struct irdma_ws_node *tc_node;
241	u16 traffic_class;
242	int ret = 0;
243	int i;
244
245	mutex_lock(&vsi->dev->ws_mutex);
246	if (vsi->tc_change_pending) {
247		ret = -EBUSY;
248		goto exit;
249	}
250
251	if (vsi->qos[user_pri].valid)
252		goto exit;
253
254	ws_tree_root = vsi->dev->ws_tree_root;
255	if (!ws_tree_root) {
256		ibdev_dbg(to_ibdev(vsi->dev), "WS: Creating root node\n");
257		ws_tree_root = irdma_alloc_node(vsi, user_pri,
258						WS_NODE_TYPE_PARENT, NULL);
259		if (!ws_tree_root) {
260			ret = -ENOMEM;
261			goto exit;
262		}
263
264		ret = irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_ADD_NODE);
265		if (ret) {
266			irdma_free_node(vsi, ws_tree_root);
267			goto exit;
268		}
269
270		vsi->dev->ws_tree_root = ws_tree_root;
271	}
272
273	/* Find a second tier node that matches the VSI */
274	vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
275				WS_MATCH_TYPE_VSI);
276
277	/* If VSI node doesn't exist, add one */
278	if (!vsi_node) {
279		ibdev_dbg(to_ibdev(vsi->dev),
280			  "WS: Node not found matching VSI %d\n",
281			  vsi->vsi_idx);
282		vsi_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_PARENT,
283					    ws_tree_root);
284		if (!vsi_node) {
285			ret = -ENOMEM;
286			goto vsi_add_err;
287		}
288
289		ret = irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_ADD_NODE);
290		if (ret) {
291			irdma_free_node(vsi, vsi_node);
292			goto vsi_add_err;
293		}
294
295		list_add(&vsi_node->siblings, &ws_tree_root->child_list_head);
296	}
297
298	ibdev_dbg(to_ibdev(vsi->dev),
299		  "WS: Using node %d which represents VSI %d\n",
300		  vsi_node->index, vsi->vsi_idx);
301	traffic_class = vsi->qos[user_pri].traffic_class;
302	tc_node = ws_find_node(vsi_node, traffic_class,
303			       WS_MATCH_TYPE_TC);
304	if (!tc_node) {
305		/* Add leaf node */
306		ibdev_dbg(to_ibdev(vsi->dev),
307			  "WS: Node not found matching VSI %d and TC %d\n",
308			  vsi->vsi_idx, traffic_class);
309		tc_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_LEAF,
310					   vsi_node);
311		if (!tc_node) {
312			ret = -ENOMEM;
313			goto leaf_add_err;
314		}
315
316		ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_ADD_NODE);
317		if (ret) {
318			irdma_free_node(vsi, tc_node);
319			goto leaf_add_err;
320		}
321
322		list_add(&tc_node->siblings, &vsi_node->child_list_head);
323		/*
324		 * callback to LAN to update the LAN tree with our node
325		 */
326		ret = vsi->register_qset(vsi, tc_node);
327		if (ret)
328			goto reg_err;
329
330		tc_node->enable = true;
331		ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_MODIFY_NODE);
332		if (ret) {
333			vsi->unregister_qset(vsi, tc_node);
334			goto reg_err;
335		}
336	}
337	ibdev_dbg(to_ibdev(vsi->dev),
338		  "WS: Using node %d which represents VSI %d TC %d\n",
339		  tc_node->index, vsi->vsi_idx, traffic_class);
340	/*
341	 * Iterate through other UPs and update the QS handle if they have
342	 * a matching traffic class.
343	 */
344	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
345		if (vsi->qos[i].traffic_class == traffic_class) {
346			vsi->qos[i].qs_handle = tc_node->qs_handle;
347			vsi->qos[i].lan_qos_handle = tc_node->lan_qs_handle;
348			vsi->qos[i].l2_sched_node_id = tc_node->l2_sched_node_id;
349			vsi->qos[i].valid = true;
350		}
351	}
352	goto exit;
353
354reg_err:
355	irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
356	list_del(&tc_node->siblings);
357	irdma_free_node(vsi, tc_node);
358leaf_add_err:
359	if (list_empty(&vsi_node->child_list_head)) {
360		if (irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE))
361			goto exit;
362		list_del(&vsi_node->siblings);
363		irdma_free_node(vsi, vsi_node);
364	}
365
366vsi_add_err:
367	/* Free head node there are no remaining VSI nodes */
368	if (list_empty(&ws_tree_root->child_list_head)) {
369		irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_DELETE_NODE);
370		vsi->dev->ws_tree_root = NULL;
371		irdma_free_node(vsi, ws_tree_root);
372	}
373
374exit:
375	mutex_unlock(&vsi->dev->ws_mutex);
 
 
 
 
 
376	return ret;
377}
378
379/**
380 * irdma_ws_remove - Free WS scheduler node, update WS tree
381 * @vsi: vsi pointer
382 * @user_pri: user priority
383 */
384void irdma_ws_remove(struct irdma_sc_vsi *vsi, u8 user_pri)
385{
386	mutex_lock(&vsi->dev->ws_mutex);
387	if (irdma_tc_in_use(vsi, user_pri))
388		goto exit;
389	irdma_remove_leaf(vsi, user_pri);
390exit:
391	mutex_unlock(&vsi->dev->ws_mutex);
392}
393
394/**
395 * irdma_ws_reset - Reset entire WS tree
396 * @vsi: vsi pointer
397 */
398void irdma_ws_reset(struct irdma_sc_vsi *vsi)
399{
400	u8 i;
401
402	mutex_lock(&vsi->dev->ws_mutex);
403	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; ++i)
404		irdma_remove_leaf(vsi, i);
405	mutex_unlock(&vsi->dev->ws_mutex);
406}
v5.14.15
  1// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
  2/* Copyright (c) 2017 - 2021 Intel Corporation */
  3#include "osdep.h"
  4#include "status.h"
  5#include "hmc.h"
  6#include "defs.h"
  7#include "type.h"
  8#include "protos.h"
  9
 10#include "ws.h"
 11
 12/**
 13 * irdma_alloc_node - Allocate a WS node and init
 14 * @vsi: vsi pointer
 15 * @user_pri: user priority
 16 * @node_type: Type of node, leaf or parent
 17 * @parent: parent node pointer
 18 */
 19static struct irdma_ws_node *irdma_alloc_node(struct irdma_sc_vsi *vsi,
 20					      u8 user_pri,
 21					      enum irdma_ws_node_type node_type,
 22					      struct irdma_ws_node *parent)
 23{
 24	struct irdma_virt_mem ws_mem;
 25	struct irdma_ws_node *node;
 26	u16 node_index = 0;
 27
 28	ws_mem.size = sizeof(struct irdma_ws_node);
 29	ws_mem.va = kzalloc(ws_mem.size, GFP_KERNEL);
 30	if (!ws_mem.va)
 31		return NULL;
 32
 33	if (parent) {
 34		node_index = irdma_alloc_ws_node_id(vsi->dev);
 35		if (node_index == IRDMA_WS_NODE_INVALID) {
 36			kfree(ws_mem.va);
 37			return NULL;
 38		}
 39	}
 40
 41	node = ws_mem.va;
 42	node->index = node_index;
 43	node->vsi_index = vsi->vsi_idx;
 44	INIT_LIST_HEAD(&node->child_list_head);
 45	if (node_type == WS_NODE_TYPE_LEAF) {
 46		node->type_leaf = true;
 47		node->traffic_class = vsi->qos[user_pri].traffic_class;
 48		node->user_pri = user_pri;
 49		node->rel_bw = vsi->qos[user_pri].rel_bw;
 50		if (!node->rel_bw)
 51			node->rel_bw = 1;
 52
 53		node->lan_qs_handle = vsi->qos[user_pri].lan_qos_handle;
 54		node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
 55	} else {
 56		node->rel_bw = 1;
 57		node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
 58		node->enable = true;
 59	}
 60
 61	node->parent = parent;
 62
 63	return node;
 64}
 65
 66/**
 67 * irdma_free_node - Free a WS node
 68 * @vsi: VSI stricture of device
 69 * @node: Pointer to node to free
 70 */
 71static void irdma_free_node(struct irdma_sc_vsi *vsi,
 72			    struct irdma_ws_node *node)
 73{
 74	struct irdma_virt_mem ws_mem;
 75
 76	if (node->index)
 77		irdma_free_ws_node_id(vsi->dev, node->index);
 78
 79	ws_mem.va = node;
 80	ws_mem.size = sizeof(struct irdma_ws_node);
 81	kfree(ws_mem.va);
 82}
 83
 84/**
 85 * irdma_ws_cqp_cmd - Post CQP work scheduler node cmd
 86 * @vsi: vsi pointer
 87 * @node: pointer to node
 88 * @cmd: add, remove or modify
 89 */
 90static enum irdma_status_code
 91irdma_ws_cqp_cmd(struct irdma_sc_vsi *vsi, struct irdma_ws_node *node, u8 cmd)
 92{
 93	struct irdma_ws_node_info node_info = {};
 94
 95	node_info.id = node->index;
 96	node_info.vsi = node->vsi_index;
 97	if (node->parent)
 98		node_info.parent_id = node->parent->index;
 99	else
100		node_info.parent_id = node_info.id;
101
102	node_info.weight = node->rel_bw;
103	node_info.tc = node->traffic_class;
104	node_info.prio_type = node->prio_type;
105	node_info.type_leaf = node->type_leaf;
106	node_info.enable = node->enable;
107	if (irdma_cqp_ws_node_cmd(vsi->dev, cmd, &node_info)) {
108		ibdev_dbg(to_ibdev(vsi->dev), "WS: CQP WS CMD failed\n");
109		return IRDMA_ERR_NO_MEMORY;
110	}
111
112	if (node->type_leaf && cmd == IRDMA_OP_WS_ADD_NODE) {
113		node->qs_handle = node_info.qs_handle;
114		vsi->qos[node->user_pri].qs_handle = node_info.qs_handle;
115	}
116
117	return 0;
118}
119
120/**
121 * ws_find_node - Find SC WS node based on VSI id or TC
122 * @parent: parent node of First VSI or TC node
123 * @match_val: value to match
124 * @type: match type VSI/TC
125 */
126static struct irdma_ws_node *ws_find_node(struct irdma_ws_node *parent,
127					  u16 match_val,
128					  enum irdma_ws_match_type type)
129{
130	struct irdma_ws_node *node;
131
132	switch (type) {
133	case WS_MATCH_TYPE_VSI:
134		list_for_each_entry(node, &parent->child_list_head, siblings) {
135			if (node->vsi_index == match_val)
136				return node;
137		}
138		break;
139	case WS_MATCH_TYPE_TC:
140		list_for_each_entry(node, &parent->child_list_head, siblings) {
141			if (node->traffic_class == match_val)
142				return node;
143		}
144		break;
145	default:
146		break;
147	}
148
149	return NULL;
150}
151
152/**
153 * irdma_tc_in_use - Checks to see if a leaf node is in use
154 * @vsi: vsi pointer
155 * @user_pri: user priority
156 */
157static bool irdma_tc_in_use(struct irdma_sc_vsi *vsi, u8 user_pri)
158{
159	int i;
160
161	mutex_lock(&vsi->qos[user_pri].qos_mutex);
162	if (!list_empty(&vsi->qos[user_pri].qplist)) {
163		mutex_unlock(&vsi->qos[user_pri].qos_mutex);
164		return true;
165	}
166
167	/* Check if the traffic class associated with the given user priority
168	 * is in use by any other user priority. If so, nothing left to do
169	 */
170	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
171		if (vsi->qos[i].traffic_class == vsi->qos[user_pri].traffic_class &&
172		    !list_empty(&vsi->qos[i].qplist)) {
173			mutex_unlock(&vsi->qos[user_pri].qos_mutex);
174			return true;
175		}
176	}
177	mutex_unlock(&vsi->qos[user_pri].qos_mutex);
178
179	return false;
180}
181
182/**
183 * irdma_remove_leaf - Remove leaf node unconditionally
184 * @vsi: vsi pointer
185 * @user_pri: user priority
186 */
187static void irdma_remove_leaf(struct irdma_sc_vsi *vsi, u8 user_pri)
188{
189	struct irdma_ws_node *ws_tree_root, *vsi_node, *tc_node;
190	int i;
191	u16 traffic_class;
192
193	traffic_class = vsi->qos[user_pri].traffic_class;
194	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++)
195		if (vsi->qos[i].traffic_class == traffic_class)
196			vsi->qos[i].valid = false;
197
198	ws_tree_root = vsi->dev->ws_tree_root;
199	if (!ws_tree_root)
200		return;
201
202	vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
203				WS_MATCH_TYPE_VSI);
204	if (!vsi_node)
205		return;
206
207	tc_node = ws_find_node(vsi_node,
208			       vsi->qos[user_pri].traffic_class,
209			       WS_MATCH_TYPE_TC);
210	if (!tc_node)
211		return;
212
213	irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
214	vsi->unregister_qset(vsi, tc_node);
215	list_del(&tc_node->siblings);
216	irdma_free_node(vsi, tc_node);
217	/* Check if VSI node can be freed */
218	if (list_empty(&vsi_node->child_list_head)) {
219		irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE);
220		list_del(&vsi_node->siblings);
221		irdma_free_node(vsi, vsi_node);
222		/* Free head node there are no remaining VSI nodes */
223		if (list_empty(&ws_tree_root->child_list_head)) {
224			irdma_ws_cqp_cmd(vsi, ws_tree_root,
225					 IRDMA_OP_WS_DELETE_NODE);
226			irdma_free_node(vsi, ws_tree_root);
227			vsi->dev->ws_tree_root = NULL;
228		}
229	}
230}
231
232/**
233 * irdma_ws_add - Build work scheduler tree, set RDMA qs_handle
234 * @vsi: vsi pointer
235 * @user_pri: user priority
236 */
237enum irdma_status_code irdma_ws_add(struct irdma_sc_vsi *vsi, u8 user_pri)
238{
239	struct irdma_ws_node *ws_tree_root;
240	struct irdma_ws_node *vsi_node;
241	struct irdma_ws_node *tc_node;
242	u16 traffic_class;
243	enum irdma_status_code ret = 0;
244	int i;
245
246	mutex_lock(&vsi->dev->ws_mutex);
247	if (vsi->tc_change_pending) {
248		ret = IRDMA_ERR_NOT_READY;
249		goto exit;
250	}
251
252	if (vsi->qos[user_pri].valid)
253		goto exit;
254
255	ws_tree_root = vsi->dev->ws_tree_root;
256	if (!ws_tree_root) {
257		ibdev_dbg(to_ibdev(vsi->dev), "WS: Creating root node\n");
258		ws_tree_root = irdma_alloc_node(vsi, user_pri,
259						WS_NODE_TYPE_PARENT, NULL);
260		if (!ws_tree_root) {
261			ret = IRDMA_ERR_NO_MEMORY;
262			goto exit;
263		}
264
265		ret = irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_ADD_NODE);
266		if (ret) {
267			irdma_free_node(vsi, ws_tree_root);
268			goto exit;
269		}
270
271		vsi->dev->ws_tree_root = ws_tree_root;
272	}
273
274	/* Find a second tier node that matches the VSI */
275	vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
276				WS_MATCH_TYPE_VSI);
277
278	/* If VSI node doesn't exist, add one */
279	if (!vsi_node) {
280		ibdev_dbg(to_ibdev(vsi->dev),
281			  "WS: Node not found matching VSI %d\n",
282			  vsi->vsi_idx);
283		vsi_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_PARENT,
284					    ws_tree_root);
285		if (!vsi_node) {
286			ret = IRDMA_ERR_NO_MEMORY;
287			goto vsi_add_err;
288		}
289
290		ret = irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_ADD_NODE);
291		if (ret) {
292			irdma_free_node(vsi, vsi_node);
293			goto vsi_add_err;
294		}
295
296		list_add(&vsi_node->siblings, &ws_tree_root->child_list_head);
297	}
298
299	ibdev_dbg(to_ibdev(vsi->dev),
300		  "WS: Using node %d which represents VSI %d\n",
301		  vsi_node->index, vsi->vsi_idx);
302	traffic_class = vsi->qos[user_pri].traffic_class;
303	tc_node = ws_find_node(vsi_node, traffic_class,
304			       WS_MATCH_TYPE_TC);
305	if (!tc_node) {
306		/* Add leaf node */
307		ibdev_dbg(to_ibdev(vsi->dev),
308			  "WS: Node not found matching VSI %d and TC %d\n",
309			  vsi->vsi_idx, traffic_class);
310		tc_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_LEAF,
311					   vsi_node);
312		if (!tc_node) {
313			ret = IRDMA_ERR_NO_MEMORY;
314			goto leaf_add_err;
315		}
316
317		ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_ADD_NODE);
318		if (ret) {
319			irdma_free_node(vsi, tc_node);
320			goto leaf_add_err;
321		}
322
323		list_add(&tc_node->siblings, &vsi_node->child_list_head);
324		/*
325		 * callback to LAN to update the LAN tree with our node
326		 */
327		ret = vsi->register_qset(vsi, tc_node);
328		if (ret)
329			goto reg_err;
330
331		tc_node->enable = true;
332		ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_MODIFY_NODE);
333		if (ret)
 
334			goto reg_err;
 
335	}
336	ibdev_dbg(to_ibdev(vsi->dev),
337		  "WS: Using node %d which represents VSI %d TC %d\n",
338		  tc_node->index, vsi->vsi_idx, traffic_class);
339	/*
340	 * Iterate through other UPs and update the QS handle if they have
341	 * a matching traffic class.
342	 */
343	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
344		if (vsi->qos[i].traffic_class == traffic_class) {
345			vsi->qos[i].qs_handle = tc_node->qs_handle;
346			vsi->qos[i].lan_qos_handle = tc_node->lan_qs_handle;
347			vsi->qos[i].l2_sched_node_id = tc_node->l2_sched_node_id;
348			vsi->qos[i].valid = true;
349		}
350	}
351	goto exit;
352
 
 
 
 
353leaf_add_err:
354	if (list_empty(&vsi_node->child_list_head)) {
355		if (irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE))
356			goto exit;
357		list_del(&vsi_node->siblings);
358		irdma_free_node(vsi, vsi_node);
359	}
360
361vsi_add_err:
362	/* Free head node there are no remaining VSI nodes */
363	if (list_empty(&ws_tree_root->child_list_head)) {
364		irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_DELETE_NODE);
365		vsi->dev->ws_tree_root = NULL;
366		irdma_free_node(vsi, ws_tree_root);
367	}
368
369exit:
370	mutex_unlock(&vsi->dev->ws_mutex);
371	return ret;
372
373reg_err:
374	mutex_unlock(&vsi->dev->ws_mutex);
375	irdma_ws_remove(vsi, user_pri);
376	return ret;
377}
378
379/**
380 * irdma_ws_remove - Free WS scheduler node, update WS tree
381 * @vsi: vsi pointer
382 * @user_pri: user priority
383 */
384void irdma_ws_remove(struct irdma_sc_vsi *vsi, u8 user_pri)
385{
386	mutex_lock(&vsi->dev->ws_mutex);
387	if (irdma_tc_in_use(vsi, user_pri))
388		goto exit;
389	irdma_remove_leaf(vsi, user_pri);
390exit:
391	mutex_unlock(&vsi->dev->ws_mutex);
392}
393
394/**
395 * irdma_ws_reset - Reset entire WS tree
396 * @vsi: vsi pointer
397 */
398void irdma_ws_reset(struct irdma_sc_vsi *vsi)
399{
400	u8 i;
401
402	mutex_lock(&vsi->dev->ws_mutex);
403	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; ++i)
404		irdma_remove_leaf(vsi, i);
405	mutex_unlock(&vsi->dev->ws_mutex);
406}