Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2017 Intel Corporation
3 : : */
4 : : #include <rte_tm_driver.h>
5 : :
6 : : #include "base/ice_sched.h"
7 : : #include "ice_dcf_ethdev.h"
8 : :
9 : : static int ice_dcf_hierarchy_commit(struct rte_eth_dev *dev,
10 : : __rte_unused int clear_on_fail,
11 : : __rte_unused struct rte_tm_error *error);
12 : : static int ice_dcf_node_add(struct rte_eth_dev *dev, uint32_t node_id,
13 : : uint32_t parent_node_id, uint32_t priority,
14 : : uint32_t weight, uint32_t level_id,
15 : : const struct rte_tm_node_params *params,
16 : : struct rte_tm_error *error);
17 : : static int ice_dcf_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
18 : : struct rte_tm_error *error);
19 : : static int ice_dcf_shaper_profile_add(struct rte_eth_dev *dev,
20 : : uint32_t shaper_profile_id,
21 : : const struct rte_tm_shaper_params *profile,
22 : : struct rte_tm_error *error);
23 : : static int ice_dcf_shaper_profile_del(struct rte_eth_dev *dev,
24 : : uint32_t shaper_profile_id,
25 : : struct rte_tm_error *error);
26 : :
27 : : const struct rte_tm_ops ice_dcf_tm_ops = {
28 : : .shaper_profile_add = ice_dcf_shaper_profile_add,
29 : : .shaper_profile_delete = ice_dcf_shaper_profile_del,
30 : : .hierarchy_commit = ice_dcf_hierarchy_commit,
31 : : .node_add = ice_dcf_node_add,
32 : : .node_delete = ice_dcf_node_delete,
33 : : };
34 : :
35 : : #define ICE_DCF_SCHED_TC_NODE 0xffff
36 : : #define ICE_DCF_VFID 0
37 : :
38 : : void
39 : 0 : ice_dcf_tm_conf_init(struct rte_eth_dev *dev)
40 : : {
41 : 0 : struct ice_dcf_adapter *adapter = dev->data->dev_private;
42 : : struct ice_dcf_hw *hw = &adapter->real_hw;
43 : :
44 : : /* initialize shaper profile list */
45 : 0 : TAILQ_INIT(&hw->tm_conf.shaper_profile_list);
46 : :
47 : : /* initialize node configuration */
48 : 0 : hw->tm_conf.root = NULL;
49 : 0 : TAILQ_INIT(&hw->tm_conf.tc_list);
50 : 0 : TAILQ_INIT(&hw->tm_conf.vsi_list);
51 : 0 : hw->tm_conf.nb_tc_node = 0;
52 : 0 : hw->tm_conf.nb_vsi_node = 0;
53 : 0 : hw->tm_conf.committed = false;
54 : 0 : }
55 : :
56 : : void
57 : 0 : ice_dcf_tm_conf_uninit(struct rte_eth_dev *dev)
58 : : {
59 : 0 : struct ice_dcf_adapter *adapter = dev->data->dev_private;
60 : : struct ice_dcf_hw *hw = &adapter->real_hw;
61 : : struct ice_dcf_tm_shaper_profile *shaper_profile;
62 : : struct ice_dcf_tm_node *tm_node;
63 : :
64 : : /* clear node configuration */
65 [ # # ]: 0 : while ((tm_node = TAILQ_FIRST(&hw->tm_conf.vsi_list))) {
66 [ # # ]: 0 : TAILQ_REMOVE(&hw->tm_conf.vsi_list, tm_node, node);
67 : 0 : rte_free(tm_node);
68 : : }
69 : 0 : hw->tm_conf.nb_vsi_node = 0;
70 [ # # ]: 0 : while ((tm_node = TAILQ_FIRST(&hw->tm_conf.tc_list))) {
71 [ # # ]: 0 : TAILQ_REMOVE(&hw->tm_conf.tc_list, tm_node, node);
72 : 0 : rte_free(tm_node);
73 : : }
74 : 0 : hw->tm_conf.nb_tc_node = 0;
75 [ # # ]: 0 : if (hw->tm_conf.root) {
76 : 0 : rte_free(hw->tm_conf.root);
77 : 0 : hw->tm_conf.root = NULL;
78 : : }
79 : :
80 : : /* Remove all shaper profiles */
81 [ # # ]: 0 : while ((shaper_profile =
82 : : TAILQ_FIRST(&hw->tm_conf.shaper_profile_list))) {
83 [ # # ]: 0 : TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,
84 : : shaper_profile, node);
85 : 0 : rte_free(shaper_profile);
86 : : }
87 : 0 : }
88 : :
89 : : static inline struct ice_dcf_tm_node *
90 : 0 : ice_dcf_tm_node_search(struct rte_eth_dev *dev,
91 : : uint32_t node_id, enum ice_dcf_tm_node_type *node_type)
92 : : {
93 : 0 : struct ice_dcf_adapter *adapter = dev->data->dev_private;
94 : : struct ice_dcf_hw *hw = &adapter->real_hw;
95 : : struct ice_dcf_tm_node_list *vsi_list = &hw->tm_conf.vsi_list;
96 : : struct ice_dcf_tm_node_list *tc_list = &hw->tm_conf.tc_list;
97 : : struct ice_dcf_tm_node *tm_node;
98 : :
99 [ # # # # ]: 0 : if (hw->tm_conf.root && hw->tm_conf.root->id == node_id) {
100 : 0 : *node_type = ICE_DCF_TM_NODE_TYPE_PORT;
101 : 0 : return hw->tm_conf.root;
102 : : }
103 : :
104 [ # # ]: 0 : TAILQ_FOREACH(tm_node, tc_list, node) {
105 [ # # ]: 0 : if (tm_node->id == node_id) {
106 : 0 : *node_type = ICE_DCF_TM_NODE_TYPE_TC;
107 : 0 : return tm_node;
108 : : }
109 : : }
110 : :
111 [ # # ]: 0 : TAILQ_FOREACH(tm_node, vsi_list, node) {
112 [ # # ]: 0 : if (tm_node->id == node_id) {
113 : 0 : *node_type = ICE_DCF_TM_NODE_TYPE_VSI;
114 : 0 : return tm_node;
115 : : }
116 : : }
117 : :
118 : : return NULL;
119 : : }
120 : :
121 : : static inline struct ice_dcf_tm_shaper_profile *
122 : : ice_dcf_shaper_profile_search(struct rte_eth_dev *dev,
123 : : uint32_t shaper_profile_id)
124 : : {
125 : : struct ice_dcf_adapter *adapter = dev->data->dev_private;
126 : : struct ice_dcf_hw *hw = &adapter->real_hw;
127 : : struct ice_dcf_shaper_profile_list *shaper_profile_list =
128 : : &hw->tm_conf.shaper_profile_list;
129 : : struct ice_dcf_tm_shaper_profile *shaper_profile;
130 : :
131 [ # # # # : 0 : TAILQ_FOREACH(shaper_profile, shaper_profile_list, node) {
# # ]
132 [ # # # # : 0 : if (shaper_profile_id == shaper_profile->shaper_profile_id)
# # ]
133 : : return shaper_profile;
134 : : }
135 : :
136 : : return NULL;
137 : : }
138 : :
139 : : static int
140 : 0 : ice_dcf_node_param_check(struct ice_dcf_hw *hw, uint32_t node_id,
141 : : uint32_t priority, uint32_t weight,
142 : : const struct rte_tm_node_params *params,
143 : : struct rte_tm_error *error)
144 : : {
145 : : /* checked all the unsupported parameter */
146 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
147 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
148 : 0 : error->message = "invalid node id";
149 : 0 : return -EINVAL;
150 : : }
151 : :
152 [ # # ]: 0 : if (priority) {
153 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PRIORITY;
154 : 0 : error->message = "priority should be 0";
155 : 0 : return -EINVAL;
156 : : }
157 : :
158 [ # # ]: 0 : if (weight != 1) {
159 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_WEIGHT;
160 : 0 : error->message = "weight must be 1";
161 : 0 : return -EINVAL;
162 : : }
163 : :
164 : : /* not support shared shaper */
165 [ # # ]: 0 : if (params->shared_shaper_id) {
166 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;
167 : 0 : error->message = "shared shaper not supported";
168 : 0 : return -EINVAL;
169 : : }
170 [ # # ]: 0 : if (params->n_shared_shapers) {
171 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;
172 : 0 : error->message = "shared shaper not supported";
173 : 0 : return -EINVAL;
174 : : }
175 : :
176 : : /* for non-leaf node */
177 [ # # ]: 0 : if (node_id >= 8 * hw->num_vfs) {
178 [ # # ]: 0 : if (params->nonleaf.wfq_weight_mode) {
179 : 0 : error->type =
180 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
181 : 0 : error->message = "WFQ not supported";
182 : 0 : return -EINVAL;
183 : : }
184 [ # # ]: 0 : if (params->nonleaf.n_sp_priorities != 1) {
185 : 0 : error->type =
186 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;
187 : 0 : error->message = "SP priority not supported";
188 : 0 : return -EINVAL;
189 : : } else if (params->nonleaf.wfq_weight_mode &&
190 : : !(*params->nonleaf.wfq_weight_mode)) {
191 : : error->type =
192 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
193 : : error->message = "WFP should be byte mode";
194 : : return -EINVAL;
195 : : }
196 : :
197 : : return 0;
198 : : }
199 : :
200 : : /* for leaf node */
201 [ # # ]: 0 : if (params->leaf.cman) {
202 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;
203 : 0 : error->message = "Congestion management not supported";
204 : 0 : return -EINVAL;
205 : : }
206 [ # # ]: 0 : if (params->leaf.wred.wred_profile_id !=
207 : : RTE_TM_WRED_PROFILE_ID_NONE) {
208 : 0 : error->type =
209 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;
210 : 0 : error->message = "WRED not supported";
211 : 0 : return -EINVAL;
212 : : }
213 [ # # ]: 0 : if (params->leaf.wred.shared_wred_context_id) {
214 : 0 : error->type =
215 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;
216 : 0 : error->message = "WRED not supported";
217 : 0 : return -EINVAL;
218 : : }
219 [ # # ]: 0 : if (params->leaf.wred.n_shared_wred_contexts) {
220 : 0 : error->type =
221 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;
222 : 0 : error->message = "WRED not supported";
223 : 0 : return -EINVAL;
224 : : }
225 : :
226 : : return 0;
227 : : }
228 : :
229 : : static int
230 : 0 : ice_dcf_node_add(struct rte_eth_dev *dev, uint32_t node_id,
231 : : uint32_t parent_node_id, uint32_t priority,
232 : : uint32_t weight, uint32_t level_id,
233 : : const struct rte_tm_node_params *params,
234 : : struct rte_tm_error *error)
235 : : {
236 : 0 : enum ice_dcf_tm_node_type parent_node_type = ICE_DCF_TM_NODE_TYPE_MAX;
237 : 0 : enum ice_dcf_tm_node_type node_type = ICE_DCF_TM_NODE_TYPE_MAX;
238 : : struct ice_dcf_tm_shaper_profile *shaper_profile = NULL;
239 : 0 : struct ice_dcf_adapter *adapter = dev->data->dev_private;
240 : : struct ice_adapter *ad = &adapter->parent;
241 : 0 : struct ice_dcf_hw *hw = &adapter->real_hw;
242 : : struct ice_dcf_tm_node *parent_node;
243 : : struct ice_dcf_tm_node *tm_node;
244 : : uint16_t tc_nb = 1;
245 : : int i, ret;
246 : :
247 [ # # ]: 0 : if (!params || !error)
248 : : return -EINVAL;
249 : :
250 : : /* if port is running */
251 [ # # ]: 0 : if (!ad->pf.adapter_stopped) {
252 : 0 : error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
253 : 0 : error->message = "port is running";
254 : 0 : return -EINVAL;
255 : : }
256 : :
257 : 0 : ret = ice_dcf_node_param_check(hw, node_id, priority, weight,
258 : : params, error);
259 [ # # ]: 0 : if (ret)
260 : : return ret;
261 : :
262 [ # # ]: 0 : for (i = 1; i < ICE_MAX_TRAFFIC_CLASS; i++) {
263 [ # # ]: 0 : if (hw->ets_config->tc_valid_bits & (1 << i))
264 : 0 : tc_nb++;
265 : : }
266 : :
267 : : /* check if the node is already existed */
268 [ # # ]: 0 : if (ice_dcf_tm_node_search(dev, node_id, &node_type)) {
269 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
270 : 0 : error->message = "node id already used";
271 : 0 : return -EINVAL;
272 : : }
273 : :
274 : : /* check the shaper profile id */
275 [ # # ]: 0 : if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
276 : : shaper_profile = ice_dcf_shaper_profile_search(dev,
277 : : params->shaper_profile_id);
278 [ # # ]: 0 : if (!shaper_profile) {
279 : 0 : error->type =
280 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;
281 : 0 : error->message = "shaper profile not exist";
282 : 0 : return -EINVAL;
283 : : }
284 : : }
285 : :
286 : : /* add root node if not have a parent */
287 [ # # ]: 0 : if (parent_node_id == RTE_TM_NODE_ID_NULL) {
288 : : /* check level */
289 [ # # ]: 0 : if (level_id != ICE_DCF_TM_NODE_TYPE_PORT) {
290 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
291 : 0 : error->message = "Wrong level";
292 : 0 : return -EINVAL;
293 : : }
294 : :
295 : : /* obviously no more than one root */
296 [ # # ]: 0 : if (hw->tm_conf.root) {
297 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
298 : 0 : error->message = "already have a root";
299 : 0 : return -EINVAL;
300 : : }
301 : :
302 : : /* add the root node */
303 : 0 : tm_node = rte_zmalloc("ice_dcf_tm_node",
304 : : sizeof(struct ice_dcf_tm_node),
305 : : 0);
306 [ # # ]: 0 : if (!tm_node)
307 : : return -ENOMEM;
308 : 0 : tm_node->id = node_id;
309 : 0 : tm_node->parent = NULL;
310 : 0 : tm_node->reference_count = 0;
311 [ # # ]: 0 : rte_memcpy(&tm_node->params, params,
312 : : sizeof(struct rte_tm_node_params));
313 : 0 : hw->tm_conf.root = tm_node;
314 : :
315 : 0 : return 0;
316 : : }
317 : :
318 : : /* TC or vsi node */
319 : : /* check the parent node */
320 : 0 : parent_node = ice_dcf_tm_node_search(dev, parent_node_id,
321 : : &parent_node_type);
322 [ # # ]: 0 : if (!parent_node) {
323 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
324 : 0 : error->message = "parent not exist";
325 : 0 : return -EINVAL;
326 : : }
327 [ # # ]: 0 : if (parent_node_type != ICE_DCF_TM_NODE_TYPE_PORT &&
328 : : parent_node_type != ICE_DCF_TM_NODE_TYPE_TC) {
329 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
330 : 0 : error->message = "parent is not port or TC";
331 : 0 : return -EINVAL;
332 : : }
333 : : /* check level */
334 [ # # ]: 0 : if (level_id != RTE_TM_NODE_LEVEL_ID_ANY &&
335 [ # # ]: 0 : level_id != (uint32_t)(parent_node_type + 1)) {
336 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
337 : 0 : error->message = "Wrong level";
338 : 0 : return -EINVAL;
339 : : }
340 : :
341 : : /* check the TC node number */
342 [ # # ]: 0 : if (parent_node_type == ICE_DCF_TM_NODE_TYPE_PORT) {
343 : : /* check the TC number */
344 [ # # ]: 0 : if (hw->tm_conf.nb_tc_node >= tc_nb) {
345 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
346 : 0 : error->message = "too many TCs";
347 : 0 : return -EINVAL;
348 : : }
349 : : } else {
350 : : /* check the vsi node number */
351 [ # # ]: 0 : if (parent_node->reference_count >= hw->num_vfs) {
352 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
353 : 0 : error->message = "too many VSI for one TC";
354 : 0 : return -EINVAL;
355 : : }
356 : : /* check the vsi node id */
357 [ # # ]: 0 : if (node_id > (uint32_t)(tc_nb * hw->num_vfs)) {
358 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
359 : 0 : error->message = "too large VSI id";
360 : 0 : return -EINVAL;
361 : : }
362 : : }
363 : :
364 : : /* add the TC or vsi node */
365 : 0 : tm_node = rte_zmalloc("ice_dcf_tm_node",
366 : : sizeof(struct ice_dcf_tm_node),
367 : : 0);
368 [ # # ]: 0 : if (!tm_node)
369 : : return -ENOMEM;
370 : 0 : tm_node->id = node_id;
371 : 0 : tm_node->priority = priority;
372 : 0 : tm_node->weight = weight;
373 : 0 : tm_node->shaper_profile = shaper_profile;
374 : 0 : tm_node->reference_count = 0;
375 : 0 : tm_node->parent = parent_node;
376 [ # # ]: 0 : rte_memcpy(&tm_node->params, params,
377 : : sizeof(struct rte_tm_node_params));
378 [ # # ]: 0 : if (parent_node_type == ICE_DCF_TM_NODE_TYPE_PORT) {
379 : 0 : TAILQ_INSERT_TAIL(&hw->tm_conf.tc_list,
380 : : tm_node, node);
381 : 0 : tm_node->tc = hw->tm_conf.nb_tc_node;
382 : 0 : hw->tm_conf.nb_tc_node++;
383 : : } else {
384 : 0 : TAILQ_INSERT_TAIL(&hw->tm_conf.vsi_list,
385 : : tm_node, node);
386 : 0 : tm_node->tc = parent_node->tc;
387 : 0 : hw->tm_conf.nb_vsi_node++;
388 : : }
389 : 0 : tm_node->parent->reference_count++;
390 : :
391 : : /* increase the reference counter of the shaper profile */
392 [ # # ]: 0 : if (shaper_profile)
393 : 0 : shaper_profile->reference_count++;
394 : :
395 : : return 0;
396 : : }
397 : :
398 : : static int
399 : 0 : ice_dcf_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
400 : : struct rte_tm_error *error)
401 : : {
402 : 0 : enum ice_dcf_tm_node_type node_type = ICE_DCF_TM_NODE_TYPE_MAX;
403 : 0 : struct ice_dcf_adapter *adapter = dev->data->dev_private;
404 : : struct ice_adapter *ad = &adapter->parent;
405 : : struct ice_dcf_hw *hw = &adapter->real_hw;
406 : : struct ice_dcf_tm_node *tm_node;
407 : :
408 [ # # ]: 0 : if (!error)
409 : : return -EINVAL;
410 : :
411 : : /* if port is running */
412 [ # # ]: 0 : if (!ad->pf.adapter_stopped) {
413 : 0 : error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
414 : 0 : error->message = "port is running";
415 : 0 : return -EINVAL;
416 : : }
417 : :
418 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
419 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
420 : 0 : error->message = "invalid node id";
421 : 0 : return -EINVAL;
422 : : }
423 : :
424 : : /* check if the node id exists */
425 : 0 : tm_node = ice_dcf_tm_node_search(dev, node_id, &node_type);
426 [ # # ]: 0 : if (!tm_node) {
427 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
428 : 0 : error->message = "no such node";
429 : 0 : return -EINVAL;
430 : : }
431 : :
432 : : /* the node should have no child */
433 [ # # ]: 0 : if (tm_node->reference_count) {
434 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
435 : 0 : error->message =
436 : : "cannot delete a node which has children";
437 : 0 : return -EINVAL;
438 : : }
439 : :
440 : : /* root node */
441 [ # # ]: 0 : if (node_type == ICE_DCF_TM_NODE_TYPE_PORT) {
442 [ # # ]: 0 : if (tm_node->shaper_profile)
443 : 0 : tm_node->shaper_profile->reference_count--;
444 : 0 : rte_free(tm_node);
445 : 0 : hw->tm_conf.root = NULL;
446 : 0 : return 0;
447 : : }
448 : :
449 : : /* TC or VSI node */
450 [ # # ]: 0 : if (tm_node->shaper_profile)
451 : 0 : tm_node->shaper_profile->reference_count--;
452 : 0 : tm_node->parent->reference_count--;
453 [ # # ]: 0 : if (node_type == ICE_DCF_TM_NODE_TYPE_TC) {
454 [ # # ]: 0 : TAILQ_REMOVE(&hw->tm_conf.tc_list, tm_node, node);
455 : 0 : hw->tm_conf.nb_tc_node--;
456 : : } else {
457 [ # # ]: 0 : TAILQ_REMOVE(&hw->tm_conf.vsi_list, tm_node, node);
458 : 0 : hw->tm_conf.nb_vsi_node--;
459 : : }
460 : 0 : rte_free(tm_node);
461 : :
462 : 0 : return 0;
463 : : }
464 : :
465 : : static int
466 : : ice_dcf_shaper_profile_param_check(const struct rte_tm_shaper_params *profile,
467 : : struct rte_tm_error *error)
468 : : {
469 : : /* min bucket size not supported */
470 [ # # ]: 0 : if (profile->committed.size) {
471 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;
472 : 0 : error->message = "committed bucket size not supported";
473 : : return -EINVAL;
474 : : }
475 : : /* max bucket size not supported */
476 [ # # ]: 0 : if (profile->peak.size) {
477 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;
478 : 0 : error->message = "peak bucket size not supported";
479 : : return -EINVAL;
480 : : }
481 : : /* length adjustment not supported */
482 [ # # ]: 0 : if (profile->pkt_length_adjust) {
483 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;
484 : 0 : error->message = "packet length adjustment not supported";
485 : : return -EINVAL;
486 : : }
487 : :
488 : : return 0;
489 : : }
490 : :
491 : : static int
492 : 0 : ice_dcf_shaper_profile_add(struct rte_eth_dev *dev,
493 : : uint32_t shaper_profile_id,
494 : : const struct rte_tm_shaper_params *profile,
495 : : struct rte_tm_error *error)
496 : : {
497 : 0 : struct ice_dcf_adapter *adapter = dev->data->dev_private;
498 : : struct ice_dcf_hw *hw = &adapter->real_hw;
499 : : struct ice_dcf_tm_shaper_profile *shaper_profile;
500 : : int ret;
501 : :
502 [ # # ]: 0 : if (!profile || !error)
503 : : return -EINVAL;
504 : :
505 : : ret = ice_dcf_shaper_profile_param_check(profile, error);
506 : : if (ret)
507 : 0 : return ret;
508 : :
509 : : shaper_profile = ice_dcf_shaper_profile_search(dev, shaper_profile_id);
510 : :
511 [ # # ]: 0 : if (shaper_profile) {
512 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
513 : 0 : error->message = "profile ID exist";
514 : 0 : return -EINVAL;
515 : : }
516 : :
517 : 0 : shaper_profile = rte_zmalloc("ice_dcf_tm_shaper_profile",
518 : : sizeof(struct ice_dcf_tm_shaper_profile),
519 : : 0);
520 [ # # ]: 0 : if (!shaper_profile)
521 : : return -ENOMEM;
522 : 0 : shaper_profile->shaper_profile_id = shaper_profile_id;
523 [ # # ]: 0 : rte_memcpy(&shaper_profile->profile, profile,
524 : : sizeof(struct rte_tm_shaper_params));
525 : 0 : TAILQ_INSERT_TAIL(&hw->tm_conf.shaper_profile_list,
526 : : shaper_profile, node);
527 : :
528 : 0 : return 0;
529 : : }
530 : :
531 : : static int
532 : 0 : ice_dcf_shaper_profile_del(struct rte_eth_dev *dev,
533 : : uint32_t shaper_profile_id,
534 : : struct rte_tm_error *error)
535 : : {
536 : 0 : struct ice_dcf_adapter *adapter = dev->data->dev_private;
537 : : struct ice_dcf_hw *hw = &adapter->real_hw;
538 : : struct ice_dcf_tm_shaper_profile *shaper_profile;
539 : :
540 [ # # ]: 0 : if (!error)
541 : : return -EINVAL;
542 : :
543 : : shaper_profile = ice_dcf_shaper_profile_search(dev, shaper_profile_id);
544 : :
545 [ # # ]: 0 : if (!shaper_profile) {
546 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
547 : 0 : error->message = "profile ID not exist";
548 : 0 : return -EINVAL;
549 : : }
550 : :
551 : : /* don't delete a profile if it's used by one or several nodes */
552 [ # # ]: 0 : if (shaper_profile->reference_count) {
553 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
554 : 0 : error->message = "profile in use";
555 : 0 : return -EINVAL;
556 : : }
557 : :
558 [ # # ]: 0 : TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list, shaper_profile, node);
559 : 0 : rte_free(shaper_profile);
560 : :
561 : 0 : return 0;
562 : : }
563 : :
564 : : static int
565 : 0 : ice_dcf_set_vf_bw(struct ice_dcf_hw *hw,
566 : : struct virtchnl_dcf_bw_cfg_list *vf_bw,
567 : : uint16_t len)
568 : : {
569 : : struct dcf_virtchnl_cmd args;
570 : : int err;
571 : :
572 : : memset(&args, 0, sizeof(args));
573 : 0 : args.v_op = VIRTCHNL_OP_DCF_CONFIG_BW;
574 : 0 : args.req_msg = (uint8_t *)vf_bw;
575 : 0 : args.req_msglen = len;
576 : 0 : err = ice_dcf_execute_virtchnl_cmd(hw, &args);
577 [ # # ]: 0 : if (err)
578 : 0 : PMD_DRV_LOG(ERR, "fail to execute command %s",
579 : : "VIRTCHNL_OP_DCF_CONFIG_BW");
580 : 0 : return err;
581 : : }
582 : :
583 : : static int
584 : 0 : ice_dcf_validate_tc_bw(struct virtchnl_dcf_bw_cfg_list *tc_bw,
585 : : uint32_t port_bw)
586 : : {
587 : : struct virtchnl_dcf_bw_cfg *cfg;
588 : : bool lowest_cir_mark = false;
589 : : u32 total_peak, rest_peak;
590 : : u32 committed, peak;
591 : : int i;
592 : :
593 : : total_peak = 0;
594 [ # # ]: 0 : for (i = 0; i < tc_bw->num_elem; i++)
595 : 0 : total_peak += tc_bw->cfg[i].shaper.peak;
596 : :
597 [ # # ]: 0 : for (i = 0; i < tc_bw->num_elem; i++) {
598 : : cfg = &tc_bw->cfg[i];
599 : 0 : peak = cfg->shaper.peak;
600 : 0 : committed = cfg->shaper.committed;
601 : 0 : rest_peak = total_peak - peak;
602 : :
603 [ # # ]: 0 : if (lowest_cir_mark && peak == 0) {
604 : 0 : PMD_DRV_LOG(ERR, "Max bandwidth must be configured for TC%u",
605 : : cfg->tc_num);
606 : 0 : return -EINVAL;
607 : : }
608 : :
609 [ # # ]: 0 : if (!lowest_cir_mark && committed)
610 : : lowest_cir_mark = true;
611 : :
612 [ # # # # ]: 0 : if (committed && committed + rest_peak > port_bw) {
613 : 0 : PMD_DRV_LOG(ERR, "Total value of TC%u min bandwidth and other TCs' max bandwidth %ukbps should be less than port link speed %ukbps",
614 : : cfg->tc_num, committed + rest_peak, port_bw);
615 : 0 : return -EINVAL;
616 : : }
617 : :
618 [ # # ]: 0 : if (committed && committed < ICE_SCHED_MIN_BW) {
619 : 0 : PMD_DRV_LOG(ERR, "If TC%u min Tx bandwidth is set, it cannot be less than 500Kbps",
620 : : cfg->tc_num);
621 : 0 : return -EINVAL;
622 : : }
623 : :
624 [ # # ]: 0 : if (peak && committed > peak) {
625 : 0 : PMD_DRV_LOG(ERR, "TC%u Min Tx bandwidth cannot be greater than max Tx bandwidth",
626 : : cfg->tc_num);
627 : 0 : return -EINVAL;
628 : : }
629 : :
630 [ # # ]: 0 : if (peak > port_bw) {
631 : 0 : PMD_DRV_LOG(ERR, "TC%u max Tx bandwidth %uKbps is greater than current link speed %uKbps",
632 : : cfg->tc_num, peak, port_bw);
633 : 0 : return -EINVAL;
634 : : }
635 : : }
636 : :
637 : : return 0;
638 : : }
639 : :
640 : 0 : static int ice_dcf_commit_check(struct ice_dcf_hw *hw)
641 : : {
642 : : struct ice_dcf_tm_node_list *tc_list = &hw->tm_conf.tc_list;
643 : : struct ice_dcf_tm_node_list *vsi_list = &hw->tm_conf.vsi_list;
644 : : struct ice_dcf_tm_node *tm_node;
645 : :
646 [ # # ]: 0 : if (!(hw->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_QOS)) {
647 : 0 : PMD_DRV_LOG(ERR, "Configure VF bandwidth is not supported");
648 : 0 : return ICE_ERR_NOT_SUPPORTED;
649 : : }
650 : :
651 : : /* check if all TC nodes are set */
652 [ # # ]: 0 : if (BIT(hw->tm_conf.nb_tc_node) & hw->ets_config->tc_valid_bits) {
653 : 0 : PMD_DRV_LOG(ERR, "Not all enabled TC nodes are set");
654 : 0 : return ICE_ERR_PARAM;
655 : : }
656 : :
657 : : /* check if all VF vsi nodes are binded to all TCs */
658 [ # # ]: 0 : TAILQ_FOREACH(tm_node, tc_list, node) {
659 [ # # ]: 0 : if (tm_node->reference_count != hw->num_vfs) {
660 : 0 : PMD_DRV_LOG(ERR, "Not all VFs are binded to TC%u",
661 : : tm_node->tc);
662 : 0 : return ICE_ERR_PARAM;
663 : : }
664 : : }
665 : :
666 : : /* check if VF vsi node id start with 0 */
667 : 0 : tm_node = TAILQ_FIRST(vsi_list);
668 [ # # ]: 0 : if (tm_node->id != 0) {
669 : 0 : PMD_DRV_LOG(ERR, "VF vsi node id must start with 0");
670 : 0 : return ICE_ERR_PARAM;
671 : : }
672 : :
673 : : return ICE_SUCCESS;
674 : : }
675 : :
676 : : int
677 : 0 : ice_dcf_replay_vf_bw(struct ice_dcf_hw *hw, uint16_t vf_id)
678 : : {
679 : : struct ice_aqc_port_ets_elem old_ets_config;
680 : : struct ice_dcf_adapter *adapter;
681 : : struct ice_hw *parent_hw;
682 : : int ret, size;
683 : :
684 : 0 : adapter = hw->eth_dev->data->dev_private;
685 : : parent_hw = &adapter->parent.hw;
686 : :
687 : : /* store the old ets config */
688 : 0 : old_ets_config = *hw->ets_config;
689 : :
690 : : ice_memset(hw->ets_config, 0, sizeof(*hw->ets_config), ICE_NONDMA_MEM);
691 : 0 : ret = ice_aq_query_port_ets(parent_hw->port_info,
692 : : hw->ets_config, sizeof(*hw->ets_config),
693 : : NULL);
694 [ # # ]: 0 : if (ret) {
695 : 0 : PMD_DRV_LOG(ERR, "DCF Query Port ETS failed");
696 : 0 : return ret;
697 : : }
698 : :
699 [ # # ]: 0 : if (memcmp(&old_ets_config, hw->ets_config, sizeof(old_ets_config))) {
700 : 0 : PMD_DRV_LOG(DEBUG, "ETS config changes, do not replay BW");
701 : 0 : return ICE_SUCCESS;
702 : : }
703 : :
704 : 0 : size = sizeof(struct virtchnl_dcf_bw_cfg_list) +
705 : : sizeof(struct virtchnl_dcf_bw_cfg) *
706 : 0 : (hw->tm_conf.nb_tc_node - 1);
707 : :
708 : 0 : ret = ice_dcf_set_vf_bw(hw, hw->qos_bw_cfg[vf_id], size);
709 [ # # ]: 0 : if (ret) {
710 : 0 : PMD_DRV_LOG(DEBUG, "VF %u BW replay failed", vf_id);
711 : 0 : return ICE_ERR_CFG;
712 : : }
713 : :
714 : : return ICE_SUCCESS;
715 : : }
716 : :
717 : : int
718 : 0 : ice_dcf_clear_bw(struct ice_dcf_hw *hw)
719 : : {
720 : : uint16_t vf_id;
721 : : uint32_t tc;
722 : : int ret, size;
723 : :
724 : 0 : size = sizeof(struct virtchnl_dcf_bw_cfg_list) +
725 : : sizeof(struct virtchnl_dcf_bw_cfg) *
726 : 0 : (hw->tm_conf.nb_tc_node - 1);
727 : :
728 [ # # ]: 0 : for (vf_id = 0; vf_id < hw->num_vfs; vf_id++) {
729 [ # # ]: 0 : for (tc = 0; tc < hw->tm_conf.nb_tc_node; tc++) {
730 : 0 : hw->qos_bw_cfg[vf_id]->cfg[tc].shaper.peak = 0;
731 : 0 : hw->qos_bw_cfg[vf_id]->cfg[tc].shaper.committed = 0;
732 : : }
733 : 0 : ret = ice_dcf_set_vf_bw(hw, hw->qos_bw_cfg[vf_id], size);
734 [ # # ]: 0 : if (ret) {
735 : 0 : PMD_DRV_LOG(DEBUG, "VF %u BW clear failed", vf_id);
736 : 0 : return ICE_ERR_CFG;
737 : : }
738 : : }
739 : :
740 : : return ICE_SUCCESS;
741 : : }
742 : :
743 : 0 : static int ice_dcf_hierarchy_commit(struct rte_eth_dev *dev,
744 : : int clear_on_fail,
745 : : __rte_unused struct rte_tm_error *error)
746 : : {
747 : 0 : struct ice_dcf_adapter *adapter = dev->data->dev_private;
748 : 0 : struct ice_dcf_hw *hw = &adapter->real_hw;
749 : : struct virtchnl_dcf_bw_cfg_list *vf_bw;
750 : : struct virtchnl_dcf_bw_cfg_list *tc_bw;
751 : : struct ice_dcf_tm_node_list *vsi_list = &hw->tm_conf.vsi_list;
752 : : struct rte_tm_shaper_params *profile;
753 : : struct ice_dcf_tm_node *tm_node;
754 : : uint32_t port_bw, cir_total;
755 : : uint16_t size, vf_id;
756 : : uint8_t num_elem = 0;
757 : : int i, ret_val;
758 : :
759 : : /* check if port is stopped */
760 [ # # ]: 0 : if (!adapter->parent.pf.adapter_stopped) {
761 : 0 : PMD_DRV_LOG(ERR, "Please stop port first");
762 : : ret_val = ICE_ERR_NOT_READY;
763 : 0 : goto err;
764 : : }
765 : :
766 : 0 : ret_val = ice_dcf_commit_check(hw);
767 [ # # ]: 0 : if (ret_val)
768 : 0 : goto fail_clear;
769 : :
770 : 0 : size = sizeof(struct virtchnl_dcf_bw_cfg_list) +
771 : : sizeof(struct virtchnl_dcf_bw_cfg) *
772 : 0 : (hw->tm_conf.nb_tc_node - 1);
773 : 0 : vf_bw = rte_zmalloc("vf_bw", size, 0);
774 [ # # ]: 0 : if (!vf_bw) {
775 : : ret_val = ICE_ERR_NO_MEMORY;
776 : 0 : goto fail_clear;
777 : : }
778 : 0 : tc_bw = rte_zmalloc("tc_bw", size, 0);
779 [ # # ]: 0 : if (!tc_bw) {
780 : : ret_val = ICE_ERR_NO_MEMORY;
781 : 0 : goto fail_clear;
782 : : }
783 : :
784 : : /* port bandwidth (Kbps) */
785 : 0 : port_bw = hw->link_speed * 1000;
786 : : cir_total = 0;
787 : :
788 : : /* init tc bw configuration */
789 : 0 : tc_bw->vf_id = ICE_DCF_SCHED_TC_NODE;
790 : 0 : tc_bw->node_type = VIRTCHNL_DCF_TARGET_TC_BW;
791 : 0 : tc_bw->num_elem = hw->tm_conf.nb_tc_node;
792 [ # # ]: 0 : for (i = 0; i < tc_bw->num_elem; i++) {
793 : 0 : tc_bw->cfg[i].tc_num = i;
794 : 0 : tc_bw->cfg[i].type = VIRTCHNL_BW_SHAPER;
795 : 0 : tc_bw->cfg[i].bw_type |=
796 : : VIRTCHNL_DCF_BW_PIR | VIRTCHNL_DCF_BW_CIR;
797 : : }
798 : :
799 : : /* start with VF1, skip VF0 since DCF does not need to configure
800 : : * bandwidth for itself
801 : : */
802 [ # # ]: 0 : for (vf_id = 1; vf_id < hw->num_vfs; vf_id++) {
803 : : num_elem = 0;
804 : 0 : vf_bw->vf_id = vf_id;
805 : 0 : vf_bw->node_type = VIRTCHNL_DCF_TARGET_VF_BW;
806 [ # # ]: 0 : TAILQ_FOREACH(tm_node, vsi_list, node) {
807 : : /* scan the nodes belong to one VSI */
808 [ # # ]: 0 : if (tm_node->id - hw->num_vfs * tm_node->tc != vf_id)
809 : 0 : continue;
810 : 0 : vf_bw->cfg[num_elem].tc_num = tm_node->tc;
811 : 0 : vf_bw->cfg[num_elem].type = VIRTCHNL_BW_SHAPER;
812 [ # # ]: 0 : if (tm_node->shaper_profile) {
813 : : /* Transfer from Byte per seconds to Kbps */
814 : : profile = &tm_node->shaper_profile->profile;
815 : 0 : vf_bw->cfg[num_elem].shaper.peak =
816 : 0 : profile->peak.rate / 1000 * BITS_PER_BYTE;
817 : 0 : vf_bw->cfg[num_elem].shaper.committed =
818 : 0 : profile->committed.rate / 1000 * BITS_PER_BYTE;
819 : 0 : vf_bw->cfg[num_elem].bw_type |=
820 : : VIRTCHNL_DCF_BW_PIR |
821 : : VIRTCHNL_DCF_BW_CIR;
822 : : }
823 : :
824 : : /* update tc node bw configuration */
825 : 0 : tc_bw->cfg[tm_node->tc].shaper.peak +=
826 : 0 : vf_bw->cfg[num_elem].shaper.peak;
827 : 0 : tc_bw->cfg[tm_node->tc].shaper.committed +=
828 : 0 : vf_bw->cfg[num_elem].shaper.committed;
829 : :
830 : 0 : cir_total += vf_bw->cfg[num_elem].shaper.committed;
831 : 0 : num_elem++;
832 : : }
833 : :
834 : 0 : vf_bw->num_elem = num_elem;
835 : 0 : ret_val = ice_dcf_set_vf_bw(hw, vf_bw, size);
836 [ # # ]: 0 : if (ret_val)
837 : 0 : goto fail_clear;
838 : :
839 : 0 : hw->qos_bw_cfg[vf_id] = rte_zmalloc("vf_bw_cfg", size, 0);
840 [ # # ]: 0 : if (!hw->qos_bw_cfg[vf_id]) {
841 : : ret_val = ICE_ERR_NO_MEMORY;
842 : 0 : goto fail_clear;
843 : : }
844 : : /* store the bandwidth information for replay */
845 : : ice_memcpy(hw->qos_bw_cfg[vf_id], vf_bw, size,
846 : : ICE_NONDMA_TO_NONDMA);
847 : : ice_memset(vf_bw, 0, size, ICE_NONDMA_MEM);
848 : : }
849 : :
850 : : /* check if total CIR is larger than port bandwidth */
851 [ # # ]: 0 : if (cir_total > port_bw) {
852 : 0 : PMD_DRV_LOG(ERR, "Total CIR of all VFs is larger than port bandwidth");
853 : : ret_val = ICE_ERR_PARAM;
854 : 0 : goto fail_clear;
855 : : }
856 : :
857 : : /* check and commit tc node bw configuration */
858 : 0 : ret_val = ice_dcf_validate_tc_bw(tc_bw, port_bw);
859 [ # # ]: 0 : if (ret_val)
860 : 0 : goto fail_clear;
861 : 0 : ret_val = ice_dcf_set_vf_bw(hw, tc_bw, size);
862 [ # # ]: 0 : if (ret_val)
863 : 0 : goto fail_clear;
864 : :
865 : : /* store TC node bw configuration */
866 : 0 : hw->qos_bw_cfg[ICE_DCF_VFID] = rte_zmalloc("tc_bw_cfg", size, 0);
867 [ # # ]: 0 : if (!hw->qos_bw_cfg[ICE_DCF_VFID]) {
868 : : ret_val = ICE_ERR_NO_MEMORY;
869 : 0 : goto fail_clear;
870 : : }
871 : : ice_memcpy(hw->qos_bw_cfg[ICE_DCF_VFID], tc_bw, size,
872 : : ICE_NONDMA_TO_NONDMA);
873 : :
874 : 0 : hw->tm_conf.committed = true;
875 : 0 : return ret_val;
876 : :
877 : 0 : fail_clear:
878 : : /* clear all the traffic manager configuration */
879 [ # # ]: 0 : if (clear_on_fail) {
880 : 0 : ice_dcf_tm_conf_uninit(dev);
881 : 0 : ice_dcf_tm_conf_init(dev);
882 : : }
883 : 0 : err:
884 : : return ret_val;
885 : : }
|