Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2021 Marvell.
3 : : */
4 : :
5 : : #include "roc_api.h"
6 : : #include "roc_priv.h"
7 : :
8 : : static inline int
9 : : bitmap_ctzll(uint64_t slab)
10 : : {
11 : 0 : if (slab == 0)
12 : : return 0;
13 : :
14 : 0 : return plt_ctz64(slab);
15 : : }
16 : :
17 : : void
18 : 0 : nix_tm_clear_shaper_profiles(struct nix *nix)
19 : : {
20 : : struct nix_tm_shaper_profile *shaper_profile, *tmp;
21 : : struct nix_tm_shaper_profile_list *list;
22 : :
23 : : list = &nix->shaper_profile_list;
24 [ # # ]: 0 : PLT_TAILQ_FOREACH_SAFE(shaper_profile, list, shaper, tmp) {
25 [ # # ]: 0 : if (shaper_profile->ref_cnt)
26 : 0 : plt_warn("Shaper profile %u has non zero references",
27 : : shaper_profile->id);
28 [ # # ]: 0 : TAILQ_REMOVE(&nix->shaper_profile_list, shaper_profile, shaper);
29 : 0 : nix_tm_shaper_profile_free(shaper_profile);
30 : : }
31 : 0 : }
32 : :
33 : : static int
34 : 0 : nix_tm_node_reg_conf(struct nix *nix, struct nix_tm_node *node)
35 : : {
36 : : uint64_t regval_mask[MAX_REGS_PER_MBOX_MSG];
37 : : uint64_t regval[MAX_REGS_PER_MBOX_MSG];
38 : : struct nix_tm_shaper_profile *profile;
39 : : uint64_t reg[MAX_REGS_PER_MBOX_MSG];
40 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
41 : : struct nix_txschq_config *req;
42 : : int rc = -EFAULT;
43 : : uint32_t hw_lvl;
44 : : uint8_t k = 0;
45 : :
46 : : memset(regval, 0, sizeof(regval));
47 : : memset(regval_mask, 0, sizeof(regval_mask));
48 : :
49 : 0 : profile = nix_tm_shaper_profile_search(nix, node->shaper_profile_id);
50 [ # # ]: 0 : hw_lvl = node->hw_lvl;
51 : :
52 : : /* Need this trigger to configure TL1 */
53 [ # # # # ]: 0 : if (!nix_tm_have_tl1_access(nix) && hw_lvl == NIX_TXSCH_LVL_TL2) {
54 : : /* Prepare default conf for TL1 */
55 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
56 : 0 : req->lvl = NIX_TXSCH_LVL_TL1;
57 : :
58 : 0 : k = nix_tm_tl1_default_prep(nix, node->parent_hw_id, req->reg,
59 : 0 : req->regval);
60 : 0 : req->num_regs = k;
61 : 0 : rc = mbox_process(mbox);
62 : : mbox_put(mbox);
63 [ # # ]: 0 : if (rc)
64 : 0 : goto error;
65 : : }
66 : :
67 : : /* Prepare topology config */
68 : 0 : k = nix_tm_topology_reg_prep(nix, node, reg, regval, regval_mask);
69 : :
70 : : /* Prepare schedule config */
71 : 0 : k += nix_tm_sched_reg_prep(nix, node, ®[k], ®val[k]);
72 : :
73 : : /* Prepare shaping config */
74 : 0 : k += nix_tm_shaper_reg_prep(node, profile, ®[k], ®val[k]);
75 : :
76 [ # # ]: 0 : if (!k)
77 : : return 0;
78 : :
79 : : /* Copy and send config mbox */
80 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
81 : 0 : req->lvl = hw_lvl;
82 : 0 : req->num_regs = k;
83 : :
84 : 0 : mbox_memcpy(req->reg, reg, sizeof(uint64_t) * k);
85 : 0 : mbox_memcpy(req->regval, regval, sizeof(uint64_t) * k);
86 : 0 : mbox_memcpy(req->regval_mask, regval_mask, sizeof(uint64_t) * k);
87 : :
88 : 0 : rc = mbox_process(mbox);
89 : : mbox_put(mbox);
90 [ # # ]: 0 : if (rc)
91 : 0 : goto error;
92 : :
93 : : return 0;
94 : 0 : error:
95 : 0 : plt_err("Txschq conf failed for node %p, rc=%d", node, rc);
96 : 0 : return rc;
97 : : }
98 : :
99 : : int
100 : 0 : nix_tm_txsch_reg_config(struct nix *nix, enum roc_nix_tm_tree tree)
101 : : {
102 : : struct nix_tm_node_list *list;
103 : : struct nix_tm_node *node;
104 : : uint32_t hw_lvl;
105 : : int rc = 0;
106 : :
107 : : list = nix_tm_node_list(nix, tree);
108 : :
109 [ # # ]: 0 : for (hw_lvl = 0; hw_lvl <= nix->tm_root_lvl; hw_lvl++) {
110 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
111 [ # # ]: 0 : if (node->hw_lvl != hw_lvl)
112 : 0 : continue;
113 : :
114 : : /* Only one TL3/TL2 Link config should have BP enable
115 : : * set per channel only for PF or lbk vf.
116 : : */
117 : 0 : node->bp_capa = 0;
118 [ # # # # ]: 0 : if (!nix->sdp_link && node->hw_lvl == nix->tm_link_cfg_lvl)
119 : 0 : node->bp_capa = 1;
120 : :
121 : 0 : rc = nix_tm_node_reg_conf(nix, node);
122 [ # # ]: 0 : if (rc)
123 : 0 : goto exit;
124 : : }
125 : : }
126 : 0 : exit:
127 : 0 : return rc;
128 : : }
129 : :
130 : : int
131 : 0 : nix_tm_update_parent_info(struct nix *nix, enum roc_nix_tm_tree tree)
132 : : {
133 : : struct nix_tm_node *child, *parent;
134 : : struct nix_tm_node_list *list;
135 : : uint32_t rr_prio, max_prio;
136 : : uint32_t rr_num = 0;
137 : :
138 : : list = nix_tm_node_list(nix, tree);
139 : :
140 : : /* Release all the node hw resources locally
141 : : * if parent marked as dirty and resource exists.
142 : : */
143 [ # # ]: 0 : TAILQ_FOREACH(child, list, node) {
144 : : /* Release resource only if parent direct hierarchy changed */
145 [ # # # # ]: 0 : if (child->flags & NIX_TM_NODE_HWRES && child->parent &&
146 [ # # ]: 0 : child->parent->child_realloc) {
147 : 0 : nix_tm_free_node_resource(nix, child);
148 : : }
149 : 0 : child->max_prio = UINT32_MAX;
150 : : }
151 : :
152 [ # # ]: 0 : TAILQ_FOREACH(parent, list, node) {
153 : : /* Count group of children of same priority i.e are RR */
154 : 0 : rr_num = nix_tm_check_rr(nix, parent->id, tree, &rr_prio,
155 : : &max_prio);
156 : :
157 : : /* Assuming that multiple RR groups are
158 : : * not configured based on capability.
159 : : */
160 : 0 : parent->rr_prio = rr_prio;
161 : 0 : parent->rr_num = rr_num;
162 : 0 : parent->max_prio = max_prio;
163 : : }
164 : :
165 : 0 : return 0;
166 : : }
167 : :
168 : : static int
169 : : nix_tm_root_node_get(struct nix *nix, int tree)
170 : : {
171 : : struct nix_tm_node_list *list = nix_tm_node_list(nix, tree);
172 : : struct nix_tm_node *tm_node;
173 : :
174 [ # # ]: 0 : TAILQ_FOREACH(tm_node, list, node) {
175 [ # # ]: 0 : if (tm_node->hw_lvl == nix->tm_root_lvl)
176 : : return 1;
177 : : }
178 : :
179 : : return 0;
180 : : }
181 : :
182 : : int
183 : 0 : nix_tm_node_add(struct roc_nix *roc_nix, struct nix_tm_node *node)
184 : : {
185 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
186 : : struct nix_tm_shaper_profile *profile;
187 : : uint32_t node_id, parent_id, lvl;
188 : : struct nix_tm_node *parent_node;
189 : : uint32_t priority, profile_id;
190 : : uint8_t hw_lvl, exp_next_lvl;
191 : : enum roc_nix_tm_tree tree;
192 : : int rc;
193 : :
194 : 0 : node_id = node->id;
195 : 0 : priority = node->priority;
196 : 0 : parent_id = node->parent_id;
197 : 0 : profile_id = node->shaper_profile_id;
198 : 0 : lvl = node->lvl;
199 : 0 : tree = node->tree;
200 : :
201 : 0 : plt_tm_dbg("Add node %s lvl %u id %u, prio 0x%x weight 0x%x "
202 : : "parent %u profile 0x%x tree %u",
203 : : nix_tm_hwlvl2str(nix_tm_lvl2nix(nix, lvl)), lvl, node_id,
204 : : priority, node->weight, parent_id, profile_id, tree);
205 : :
206 [ # # ]: 0 : if (tree >= ROC_NIX_TM_TREE_MAX)
207 : : return NIX_ERR_PARAM;
208 : :
209 : : /* Translate sw level id's to nix hw level id's */
210 : 0 : hw_lvl = nix_tm_lvl2nix(nix, lvl);
211 [ # # # # : 0 : if (hw_lvl == NIX_TXSCH_LVL_CNT && !nix_tm_is_leaf(nix, lvl))
# # ]
212 : : return NIX_ERR_TM_INVALID_LVL;
213 : :
214 : : /* Leaf nodes have to be same priority */
215 [ # # # # : 0 : if (nix_tm_is_leaf(nix, lvl) && priority != 0)
# # ]
216 : : return NIX_ERR_TM_INVALID_PRIO;
217 : :
218 : 0 : parent_node = nix_tm_node_search(nix, parent_id, tree);
219 : :
220 [ # # ]: 0 : if (node_id < nix->nb_tx_queues)
221 : : exp_next_lvl = NIX_TXSCH_LVL_SMQ;
222 : : else
223 : 0 : exp_next_lvl = hw_lvl + 1;
224 : :
225 : : /* Check if there is no parent node yet */
226 [ # # # # ]: 0 : if (hw_lvl != nix->tm_root_lvl &&
227 [ # # ]: 0 : (!parent_node || parent_node->hw_lvl != exp_next_lvl))
228 : : return NIX_ERR_TM_INVALID_PARENT;
229 : :
230 : : /* Check if a node already exists */
231 [ # # ]: 0 : if (nix_tm_node_search(nix, node_id, tree))
232 : : return NIX_ERR_TM_NODE_EXISTS;
233 : :
234 : : /* Check if root node exists */
235 [ # # # # ]: 0 : if (hw_lvl == nix->tm_root_lvl && nix_tm_root_node_get(nix, tree))
236 : : return NIX_ERR_TM_NODE_EXISTS;
237 : :
238 : 0 : profile = nix_tm_shaper_profile_search(nix, profile_id);
239 [ # # ]: 0 : if (!nix_tm_is_leaf(nix, lvl)) {
240 : : /* Check if shaper profile exists for non leaf node */
241 [ # # ]: 0 : if (!profile && profile_id != ROC_NIX_TM_SHAPER_PROFILE_NONE)
242 : : return NIX_ERR_TM_INVALID_SHAPER_PROFILE;
243 : :
244 : : /* Packet mode in profile should match with that of tm node */
245 [ # # # # ]: 0 : if (profile && profile->pkt_mode != node->pkt_mode)
246 : : return NIX_ERR_TM_PKT_MODE_MISMATCH;
247 : : }
248 : :
249 : : /* Check if there is second DWRR already in siblings or holes in prio */
250 : 0 : rc = nix_tm_validate_prio(nix, lvl, parent_id, priority, tree);
251 [ # # ]: 0 : if (rc)
252 : : return rc;
253 : :
254 [ # # # # ]: 0 : if (node->weight > roc_nix_tm_max_sched_wt_get())
255 : : return NIX_ERR_TM_WEIGHT_EXCEED;
256 : :
257 : 0 : node->hw_lvl = nix_tm_lvl2nix(nix, lvl);
258 : 0 : node->rr_prio = 0xF;
259 : 0 : node->max_prio = UINT32_MAX;
260 : 0 : node->hw_id = NIX_TM_HW_ID_INVALID;
261 : 0 : node->flags = 0;
262 : :
263 [ # # ]: 0 : if (profile)
264 : 0 : profile->ref_cnt++;
265 : :
266 : 0 : node->parent = parent_node;
267 [ # # ]: 0 : if (parent_node)
268 : 0 : parent_node->child_realloc = true;
269 : 0 : node->parent_hw_id = NIX_TM_HW_ID_INVALID;
270 : :
271 [ # # # # : 0 : TAILQ_INSERT_TAIL(&nix->trees[tree], node, node);
# # ]
272 : 0 : plt_tm_dbg("Added node %s lvl %u id %u (%p)",
273 : : nix_tm_hwlvl2str(node->hw_lvl), lvl, node_id, node);
274 : 0 : return 0;
275 : : }
276 : :
277 : : int
278 : 0 : nix_tm_clear_path_xoff(struct nix *nix, struct nix_tm_node *node)
279 : : {
280 : 0 : struct mbox *mbox = mbox_get((&nix->dev)->mbox);
281 : : struct nix_txschq_config *req;
282 : : struct nix_tm_node *p;
283 : : int rc;
284 : :
285 : : /* Enable nodes in path for flush to succeed */
286 [ # # # # ]: 0 : if (!nix_tm_is_leaf(nix, node->lvl))
287 : : p = node;
288 : : else
289 : 0 : p = node->parent;
290 [ # # ]: 0 : while (p) {
291 [ # # ]: 0 : if (!(p->flags & NIX_TM_NODE_ENABLED) &&
292 : : (p->flags & NIX_TM_NODE_HWRES)) {
293 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox);
294 : 0 : req->lvl = p->hw_lvl;
295 : 0 : req->num_regs = nix_tm_sw_xoff_prep(p, false, req->reg,
296 : 0 : req->regval);
297 : 0 : rc = mbox_process(mbox);
298 [ # # ]: 0 : if (rc)
299 : 0 : goto exit;
300 : :
301 : 0 : p->flags |= NIX_TM_NODE_ENABLED;
302 : : }
303 : 0 : p = p->parent;
304 : : }
305 : :
306 : : rc = 0;
307 : 0 : exit:
308 : : mbox_put(mbox);
309 : 0 : return rc;
310 : : }
311 : :
312 : : int
313 [ # # ]: 0 : nix_tm_bp_config_set(struct roc_nix *roc_nix, uint16_t sq, uint16_t tc,
314 : : bool enable)
315 : : {
316 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
317 : 0 : enum roc_nix_tm_tree tree = nix->tm_tree;
318 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
319 : : struct nix_txschq_config *req = NULL;
320 : : struct nix_tm_node_list *list;
321 : 0 : uint16_t link = nix->tx_link;
322 : : struct nix_tm_node *sq_node;
323 : : struct nix_tm_node *parent;
324 : : struct nix_tm_node *node;
325 : : struct roc_nix_sq *sq_s;
326 : : uint16_t rel_chan = 0;
327 : : uint8_t parent_lvl;
328 : : uint8_t k = 0;
329 : : int rc = 0, i;
330 : :
331 : 0 : sq_s = nix->sqs[sq];
332 [ # # ]: 0 : if (!sq_s)
333 : : return -ENOENT;
334 : :
335 : 0 : sq_node = nix_tm_node_search(nix, sq, nix->tm_tree);
336 [ # # ]: 0 : if (!sq_node)
337 : : return -ENOENT;
338 : :
339 [ # # ]: 0 : parent_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH2 :
340 : : ROC_TM_LVL_SCH1);
341 : :
342 : 0 : parent = sq_node->parent;
343 [ # # ]: 0 : while (parent) {
344 [ # # ]: 0 : if (parent->lvl == parent_lvl)
345 : : break;
346 : :
347 : 0 : parent = parent->parent;
348 : : }
349 [ # # ]: 0 : if (!parent)
350 : : return -ENOENT;
351 : :
352 : : list = nix_tm_node_list(nix, tree);
353 : :
354 : : /* Get relative channel if loopback */
355 [ # # ]: 0 : if (roc_nix_is_lbk(roc_nix))
356 : 0 : rel_chan = nix_tm_lbk_relchan_get(nix);
357 : : else
358 : : rel_chan = tc;
359 : :
360 : : /* Enable request, parent rel chan already configured */
361 [ # # # # : 0 : if (enable && parent->rel_chan != NIX_TM_CHAN_INVALID &&
# # ]
362 : : parent->rel_chan != rel_chan) {
363 : 0 : plt_err("SQ %d: parent node TL3 id %d already has rel_chan %d set",
364 : : sq, parent->hw_id, parent->rel_chan);
365 : : rc = -EINVAL;
366 : 0 : goto err;
367 : : }
368 : :
369 : : /* No action if enable request for a non participating SQ. This case is
370 : : * required to handle post flush where TCs should be reconfigured after
371 : : * pre flush.
372 : : */
373 [ # # # # : 0 : if (enable && sq_s->tc == ROC_NIX_PFC_CLASS_INVALID &&
# # ]
374 : : tc == ROC_NIX_PFC_CLASS_INVALID)
375 : : return 0;
376 : :
377 : : /* Find the parent TL3 */
378 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
379 [ # # ]: 0 : if (node->hw_lvl != nix->tm_link_cfg_lvl)
380 : 0 : continue;
381 : :
382 [ # # # # ]: 0 : if (!(node->flags & NIX_TM_NODE_HWRES) || !node->bp_capa)
383 : 0 : continue;
384 : :
385 : : /* Restrict sharing of TL3 across the queues */
386 [ # # # # ]: 0 : if (enable && node != parent && node->rel_chan == rel_chan) {
387 : 0 : plt_warn("SQ %d: siblng node TL3 %d already has %d(%d) tc value set",
388 : : sq, node->hw_id, tc, rel_chan);
389 : 0 : return -EEXIST;
390 : : }
391 : : }
392 : :
393 : : /* Allocating TL3 request */
394 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
395 : 0 : req->lvl = nix->tm_link_cfg_lvl;
396 : : k = 0;
397 : :
398 : : /* Enable PFC/pause on the identified TL3 */
399 : 0 : req->reg[k] = NIX_AF_TL3_TL2X_LINKX_CFG(parent->hw_id, link);
400 [ # # ]: 0 : req->regval[k] = enable ? rel_chan : 0;
401 [ # # ]: 0 : req->regval[k] |= enable ? BIT_ULL(13) : 0;
402 : 0 : req->regval_mask[k] = ~(BIT_ULL(13) | GENMASK_ULL(7, 0));
403 : : k++;
404 : :
405 : 0 : req->num_regs = k;
406 : 0 : rc = mbox_process(mbox);
407 [ # # ]: 0 : if (rc)
408 : 0 : goto err;
409 : :
410 [ # # ]: 0 : parent->rel_chan = enable ? rel_chan : NIX_TM_CHAN_INVALID;
411 [ # # ]: 0 : sq_s->tc = enable ? tc : ROC_NIX_PFC_CLASS_INVALID;
412 : : /* Clear other SQ's with same TC i.e same parent node */
413 [ # # # # ]: 0 : for (i = 0; !enable && i < nix->nb_tx_queues; i++) {
414 [ # # # # ]: 0 : if (nix->sqs[i] && nix->sqs[i]->tc == tc)
415 : 0 : nix->sqs[i]->tc = ROC_NIX_PFC_CLASS_INVALID;
416 : : }
417 : :
418 : : rc = 0;
419 [ # # ]: 0 : plt_tm_dbg("SQ %u: TL3 %d TC %u %s",
420 : : sq, parent->hw_id, tc, enable ? "enabled" : "disabled");
421 : 0 : goto exit;
422 : 0 : err:
423 [ # # ]: 0 : plt_err("Failed to %s bp on link %u, rc=%d(%s)",
424 : : enable ? "enable" : "disable", link, rc, roc_error_msg_get(rc));
425 : 0 : exit:
426 : : mbox_put(mbox);
427 : 0 : return rc;
428 : : }
429 : :
430 : : int
431 : 0 : nix_tm_bp_config_get(struct roc_nix *roc_nix, bool *is_enabled)
432 : : {
433 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
434 : : struct nix_txschq_config *req = NULL, *rsp;
435 : 0 : enum roc_nix_tm_tree tree = nix->tm_tree;
436 : 0 : struct mbox *mbox = mbox_get((&nix->dev)->mbox);
437 : : struct nix_tm_node_list *list;
438 : : struct nix_tm_node *node;
439 : : bool found = false;
440 : : uint8_t enable = 1;
441 : : uint8_t k = 0, i;
442 : : uint16_t link;
443 : : int rc = 0;
444 : :
445 : : list = nix_tm_node_list(nix, tree);
446 : 0 : link = nix->tx_link;
447 : :
448 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
449 [ # # ]: 0 : if (node->hw_lvl != nix->tm_link_cfg_lvl)
450 : 0 : continue;
451 : :
452 [ # # # # ]: 0 : if (!(node->flags & NIX_TM_NODE_HWRES) || !node->bp_capa)
453 : 0 : continue;
454 : :
455 : : found = true;
456 [ # # ]: 0 : if (!req) {
457 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox);
458 : 0 : req->read = 1;
459 : 0 : req->lvl = nix->tm_link_cfg_lvl;
460 : : k = 0;
461 : : }
462 : :
463 : 0 : req->reg[k] = NIX_AF_TL3_TL2X_LINKX_CFG(node->hw_id, link);
464 : 0 : k++;
465 : :
466 [ # # ]: 0 : if (k >= MAX_REGS_PER_MBOX_MSG) {
467 : 0 : req->num_regs = k;
468 : : rc = mbox_process_msg(mbox, (void **)&rsp);
469 [ # # # # ]: 0 : if (rc || rsp->num_regs != k)
470 : 0 : goto err;
471 : : req = NULL;
472 : :
473 : : /* Report it as enabled only if enabled or all */
474 [ # # ]: 0 : for (i = 0; i < k; i++)
475 : 0 : enable &= !!(rsp->regval[i] & BIT_ULL(13));
476 : : }
477 : : }
478 : :
479 [ # # ]: 0 : if (req) {
480 : 0 : req->num_regs = k;
481 : : rc = mbox_process_msg(mbox, (void **)&rsp);
482 [ # # ]: 0 : if (rc)
483 : 0 : goto err;
484 : : /* Report it as enabled only if enabled or all */
485 [ # # ]: 0 : for (i = 0; i < k; i++)
486 : 0 : enable &= !!(rsp->regval[i] & BIT_ULL(13));
487 : : }
488 : :
489 : 0 : *is_enabled = found ? !!enable : false;
490 : : rc = 0;
491 : 0 : goto exit;
492 : 0 : err:
493 : 0 : plt_err("Failed to get bp status on link %u, rc=%d(%s)", link, rc,
494 : : roc_error_msg_get(rc));
495 : 0 : exit:
496 : : mbox_put(mbox);
497 : 0 : return rc;
498 : : }
499 : :
500 : : int
501 : 0 : nix_tm_smq_xoff(struct nix *nix, struct nix_tm_node *node, bool enable)
502 : : {
503 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
504 : : struct nix_txschq_config *req;
505 : : uint16_t smq;
506 : : int rc;
507 : :
508 : 0 : smq = node->hw_id;
509 [ # # ]: 0 : plt_tm_dbg("Setting SMQ %u XOFF/FLUSH to %s", smq,
510 : : enable ? "enable" : "disable");
511 : :
512 : 0 : rc = nix_tm_clear_path_xoff(nix, node);
513 [ # # ]: 0 : if (rc)
514 : : return rc;
515 : :
516 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
517 : 0 : req->lvl = NIX_TXSCH_LVL_SMQ;
518 : 0 : req->num_regs = 1;
519 : :
520 : 0 : req->reg[0] = NIX_AF_SMQX_CFG(smq);
521 [ # # ]: 0 : req->regval[0] = enable ? (BIT_ULL(50) | BIT_ULL(49)) : 0;
522 : 0 : req->regval_mask[0] =
523 [ # # ]: 0 : enable ? ~(BIT_ULL(50) | BIT_ULL(49)) : ~BIT_ULL(50);
524 : :
525 : 0 : rc = mbox_process(mbox);
526 : : mbox_put(mbox);
527 : 0 : return rc;
528 : : }
529 : :
530 : : int
531 : 0 : nix_tm_leaf_data_get(struct nix *nix, uint16_t sq, uint32_t *rr_quantum,
532 : : uint16_t *smq)
533 : : {
534 : : struct nix_tm_node *node;
535 : : int rc;
536 : :
537 : 0 : node = nix_tm_node_search(nix, sq, nix->tm_tree);
538 : :
539 : : /* Check if we found a valid leaf node */
540 [ # # # # : 0 : if (!node || !nix_tm_is_leaf(nix, node->lvl) || !node->parent ||
# # # # ]
541 [ # # ]: 0 : node->parent->hw_id == NIX_TM_HW_ID_INVALID) {
542 : : return -EIO;
543 : : }
544 : :
545 : : /* Get SMQ Id of leaf node's parent */
546 : 0 : *smq = node->parent->hw_id;
547 [ # # ]: 0 : *rr_quantum = nix_tm_weight_to_rr_quantum(node->weight);
548 : :
549 : 0 : rc = nix_tm_smq_xoff(nix, node->parent, false);
550 [ # # ]: 0 : if (rc)
551 : : return rc;
552 : 0 : node->flags |= NIX_TM_NODE_ENABLED;
553 : 0 : return 0;
554 : : }
555 : :
556 : : int
557 : 0 : roc_nix_tm_sq_flush_spin(struct roc_nix_sq *sq)
558 : : {
559 : 0 : struct nix *nix = roc_nix_to_nix_priv(sq->roc_nix);
560 : : uint16_t sqb_cnt, head_off, tail_off;
561 : : uint64_t wdata, val, prev;
562 : : uint16_t qid = sq->qid;
563 : : int64_t *regaddr;
564 : : uint64_t timeout; /* 10's of usec */
565 : :
566 : : /* Wait for enough time based on shaper min rate */
567 : 0 : timeout = (sq->nb_desc * roc_nix_max_pkt_len(sq->roc_nix) * 8 * 1E5);
568 : : /* Wait for worst case scenario of this SQ being last priority
569 : : * and so have to wait for all other SQ's drain out by their own.
570 : : */
571 : 0 : timeout = timeout * nix->nb_tx_queues;
572 : 0 : timeout = timeout / nix->tm_rate_min;
573 [ # # ]: 0 : if (!timeout)
574 : : timeout = 10000;
575 : :
576 : : wdata = ((uint64_t)qid << 32);
577 : : regaddr = (int64_t *)(nix->base + NIX_LF_SQ_OP_STATUS);
578 : : val = roc_atomic64_add_nosync(wdata, regaddr);
579 : :
580 : : /* Spin multiple iterations as "sq->fc_cache_pkts" can still
581 : : * have space to send pkts even though fc_mem is disabled
582 : : */
583 : :
584 : : while (true) {
585 : : prev = val;
586 : 0 : plt_delay_us(10);
587 : : val = roc_atomic64_add_nosync(wdata, regaddr);
588 : : /* Continue on error */
589 : : if (val & BIT_ULL(63))
590 : : continue;
591 : :
592 : : if (prev != val)
593 : : continue;
594 : :
595 : : sqb_cnt = val & 0xFFFF;
596 : : head_off = (val >> 20) & 0x3F;
597 : : tail_off = (val >> 28) & 0x3F;
598 : :
599 : : /* SQ reached quiescent state */
600 : 0 : if (sqb_cnt <= 1 && head_off == tail_off &&
601 [ # # ]: 0 : (*(volatile uint64_t *)sq->fc == sq->aura_sqb_bufs)) {
602 : : break;
603 : : }
604 : :
605 : : /* Timeout */
606 [ # # ]: 0 : if (!timeout)
607 : 0 : goto exit;
608 : 0 : timeout--;
609 : : }
610 : :
611 : : return 0;
612 : : exit:
613 : 0 : return -EFAULT;
614 : : }
615 : :
616 : : void
617 : 0 : nix_tm_sq_free_sqe_buffer(uint64_t *sqe, int head_off, int end_off, int instr_sz)
618 : : {
619 : 0 : int i, j, inc = (8 * (0x2 >> instr_sz)), segs;
620 : : struct nix_send_hdr_s *send_hdr;
621 : : uint64_t *ptr, aura_handle;
622 : : struct idev_cfg *idev;
623 : :
624 [ # # ]: 0 : if (!sqe)
625 : : return;
626 : :
627 : 0 : idev = idev_get_cfg();
628 [ # # ]: 0 : if (idev == NULL)
629 : : return;
630 : :
631 : : ptr = sqe + (head_off * inc);
632 [ # # ]: 0 : for (i = head_off; i < end_off; i++) {
633 : 0 : ptr = sqe + (i * inc);
634 : : send_hdr = (struct nix_send_hdr_s *)(ptr);
635 [ # # ]: 0 : aura_handle = roc_npa_aura_handle_gen(send_hdr->w0.aura, idev->npa->base);
636 : 0 : ptr += 2;
637 [ # # ]: 0 : if (((*ptr >> 60) & 0xF) == NIX_SUBDC_EXT)
638 : 0 : ptr += 2;
639 [ # # ]: 0 : if (((*ptr >> 60) & 0xF) == NIX_SUBDC_AGE_AND_STATS)
640 : 0 : ptr += 2;
641 [ # # ]: 0 : if (((*ptr >> 60) & 0xF) == NIX_SUBDC_JUMP) {
642 : : ptr += 1;
643 : 0 : ptr = (uint64_t *)*ptr;
644 : : }
645 [ # # ]: 0 : if (((*ptr >> 60) & 0xF) == NIX_SUBDC_CRC)
646 : 0 : ptr += 2;
647 : : /* We are not parsing immediate send descriptor */
648 [ # # ]: 0 : if (((*ptr >> 60) & 0xF) == NIX_SUBDC_IMM)
649 : 0 : continue;
650 : : while (1) {
651 [ # # ]: 0 : if (((*ptr >> 60) & 0xF) == NIX_SUBDC_SG) {
652 : 0 : segs = (*ptr >> 48) & 0x3;
653 : 0 : ptr += 1;
654 [ # # ]: 0 : for (j = 0; j < segs; j++) {
655 : 0 : roc_npa_aura_op_free(aura_handle, 0, *ptr);
656 : 0 : ptr += 1;
657 : : }
658 [ # # ]: 0 : if (segs == 2)
659 : 0 : ptr += 1;
660 [ # # ]: 0 : } else if (((*ptr >> 60) & 0xF) == NIX_SUBDC_SG2) {
661 : 0 : uint64_t aura = (*ptr >> 16) & 0xFFFFF;
662 : :
663 : 0 : aura = roc_npa_aura_handle_gen(aura, idev->npa->base);
664 : : ptr += 1;
665 : 0 : roc_npa_aura_op_free(aura, 0, *ptr);
666 : 0 : ptr += 1;
667 : : } else
668 : : break;
669 : : }
670 : : }
671 : : }
672 : :
673 : : int
674 : 0 : roc_nix_tm_sq_free_pending_sqe(struct nix *nix, int q)
675 : : {
676 : : int head_off, count, rc = 0, tail_off;
677 : 0 : struct roc_nix_sq *sq = nix->sqs[q];
678 : : void *sqb_buf, *dat, *tail_sqb;
679 : 0 : struct dev *dev = &nix->dev;
680 : : struct ndc_sync_op *ndc_req;
681 : : uint16_t sqes_per_sqb;
682 : : struct mbox *mbox;
683 : :
684 : 0 : mbox = dev->mbox;
685 : : /* Sync NDC-NIX-TX for LF */
686 : 0 : ndc_req = mbox_alloc_msg_ndc_sync_op(mbox_get(mbox));
687 [ # # ]: 0 : if (ndc_req == NULL) {
688 : : mbox_put(mbox);
689 : 0 : return -EFAULT;
690 : : }
691 : :
692 : 0 : ndc_req->nix_lf_tx_sync = 1;
693 [ # # ]: 0 : if (mbox_process(mbox))
694 : : rc |= NIX_ERR_NDC_SYNC;
695 : : mbox_put(mbox);
696 : :
697 [ # # ]: 0 : if (rc)
698 : 0 : plt_err("NDC_SYNC failed rc %d", rc);
699 : :
700 : 0 : rc = nix_q_ctx_get(dev, NIX_AQ_CTYPE_SQ, q, (void *)&dat);
701 : :
702 [ # # ]: 0 : if (roc_model_is_cn9k()) {
703 : 0 : volatile struct nix_sq_ctx_s *ctx = (struct nix_sq_ctx_s *)dat;
704 : :
705 : : /* We will cleanup SQE buffers only when we received MNQ interrupt */
706 [ # # ]: 0 : if (!ctx->mnq_dis)
707 : : return -EFAULT;
708 : :
709 : 0 : count = ctx->sqb_count;
710 : 0 : sqb_buf = (void *)ctx->head_sqb;
711 : 0 : tail_sqb = (void *)ctx->tail_sqb;
712 : 0 : head_off = ctx->head_offset;
713 : 0 : tail_off = ctx->tail_offset;
714 : : } else {
715 : 0 : volatile struct nix_cn10k_sq_ctx_s *ctx = (struct nix_cn10k_sq_ctx_s *)dat;
716 : :
717 : : /* We will cleanup SQE buffers only when we received MNQ interrupt */
718 [ # # ]: 0 : if (!ctx->mnq_dis)
719 : : return -EFAULT;
720 : :
721 : 0 : count = ctx->sqb_count;
722 : : /* Free SQB's that are used */
723 : 0 : sqb_buf = (void *)ctx->head_sqb;
724 : 0 : tail_sqb = (void *)ctx->tail_sqb;
725 : 0 : head_off = ctx->head_offset;
726 : 0 : tail_off = ctx->tail_offset;
727 : : }
728 : 0 : sqes_per_sqb = 1 << sq->sqes_per_sqb_log2;
729 : : /* Free SQB's that are used */
730 [ # # ]: 0 : while (count) {
731 : : void *next_sqb;
732 : :
733 [ # # ]: 0 : if (sqb_buf == tail_sqb)
734 : 0 : nix_tm_sq_free_sqe_buffer(sqb_buf, head_off, tail_off, sq->max_sqe_sz);
735 : : else
736 : 0 : nix_tm_sq_free_sqe_buffer(sqb_buf, head_off, (sqes_per_sqb - 1),
737 : 0 : sq->max_sqe_sz);
738 : 0 : next_sqb = *(void **)((uint64_t *)sqb_buf +
739 : 0 : (uint32_t)((sqes_per_sqb - 1) * (0x2 >> sq->max_sqe_sz) * 8));
740 : 0 : roc_npa_aura_op_free(sq->aura_handle, 1, (uint64_t)sqb_buf);
741 : : sqb_buf = next_sqb;
742 : : head_off = 0;
743 : 0 : count--;
744 : : }
745 : :
746 : : return 0;
747 : : }
748 : :
749 : : static inline int
750 : 0 : nix_tm_sdp_sq_drop_pkts(struct roc_nix *roc_nix, struct roc_nix_sq *sq)
751 : : {
752 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
753 : 0 : struct mbox *mbox = mbox_get((&nix->dev)->mbox);
754 : : struct nix_txschq_config *req = NULL, *rsp;
755 : 0 : enum roc_nix_tm_tree tree = nix->tm_tree;
756 : 0 : int rc = 0, qid = sq->qid;
757 : : struct nix_tm_node *node;
758 : : uint64_t regval;
759 : :
760 : : /* Find the node for this SQ */
761 : 0 : node = nix_tm_node_search(nix, qid, tree);
762 [ # # ]: 0 : while (node) {
763 [ # # ]: 0 : if (node->hw_lvl != NIX_TXSCH_LVL_TL4) {
764 : 0 : node = node->parent;
765 : 0 : continue;
766 : : }
767 : : break;
768 : : }
769 [ # # ]: 0 : if (!node) {
770 : 0 : plt_err("Invalid node/state for sq %u", qid);
771 : 0 : return -EFAULT;
772 : : }
773 : :
774 : : /* Get present link config */
775 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox);
776 : 0 : req->read = 1;
777 : 0 : req->lvl = NIX_TXSCH_LVL_TL4;
778 : 0 : req->reg[0] = NIX_AF_TL4X_SDP_LINK_CFG(node->hw_id);
779 : 0 : req->num_regs = 1;
780 : : rc = mbox_process_msg(mbox, (void **)&rsp);
781 [ # # # # ]: 0 : if (rc || rsp->num_regs != 1)
782 : 0 : goto err;
783 : 0 : regval = rsp->regval[0];
784 : : /* Disable BP_ENA in SDP link config */
785 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox);
786 : 0 : req->lvl = NIX_TXSCH_LVL_TL4;
787 : 0 : req->reg[0] = NIX_AF_TL4X_SDP_LINK_CFG(node->hw_id);
788 : 0 : req->regval[0] = 0x0ull;
789 : 0 : req->regval_mask[0] = ~(BIT_ULL(13));
790 : 0 : req->num_regs = 1;
791 : 0 : rc = mbox_process(mbox);
792 [ # # ]: 0 : if (rc)
793 : 0 : goto err;
794 : : mbox_put(mbox);
795 : : /* Flush SQ to drop all packets */
796 : 0 : rc = roc_nix_tm_sq_flush_spin(sq);
797 [ # # ]: 0 : if (rc)
798 : 0 : plt_nix_dbg("SQ flush failed with link reset config rc %d", rc);
799 : 0 : mbox = mbox_get((&nix->dev)->mbox);
800 : : /* Restore link config */
801 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox);
802 : 0 : req->reg[0] = NIX_AF_TL4X_SDP_LINK_CFG(node->hw_id);
803 : 0 : req->lvl = NIX_TXSCH_LVL_TL4;
804 : 0 : req->regval[0] = regval;
805 : 0 : req->regval_mask[0] = ~(BIT_ULL(13) | BIT_ULL(12) | GENMASK_ULL(7, 0));
806 : 0 : req->num_regs = 1;
807 : 0 : rc = mbox_process(mbox);
808 : 0 : err:
809 : : mbox_put(mbox);
810 : 0 : return rc;
811 : : }
812 : :
813 : : /* Flush and disable tx queue and its parent SMQ */
814 : : int
815 : 0 : nix_tm_sq_flush_pre(struct roc_nix_sq *sq)
816 : : {
817 [ # # ]: 0 : struct roc_nix *roc_nix = sq->roc_nix;
818 : : struct nix_tm_node *node, *sibling;
819 : : struct nix_tm_node_list *list;
820 : : enum roc_nix_tm_tree tree;
821 : : struct msg_req *req;
822 : : struct mbox *mbox;
823 : : struct nix *nix;
824 : : uint16_t qid;
825 : : int rc;
826 : :
827 : : nix = roc_nix_to_nix_priv(roc_nix);
828 : :
829 : : /* Need not do anything if tree is in disabled state */
830 [ # # ]: 0 : if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
831 : : return 0;
832 : :
833 : 0 : mbox = (&nix->dev)->mbox;
834 : 0 : qid = sq->qid;
835 : :
836 : 0 : tree = nix->tm_tree;
837 : : list = nix_tm_node_list(nix, tree);
838 : :
839 : : /* Find the node for this SQ */
840 : 0 : node = nix_tm_node_search(nix, qid, tree);
841 [ # # ]: 0 : if (!node) {
842 : 0 : plt_err("Invalid node/state for sq %u", qid);
843 : 0 : return -EFAULT;
844 : : }
845 : :
846 : : /* Enable CGX RXTX to drain pkts */
847 [ # # ]: 0 : if (!roc_nix->io_enabled) {
848 : : /* Though it enables both RX MCAM Entries and CGX Link
849 : : * we assume all the rx queues are stopped way back.
850 : : */
851 : 0 : mbox_alloc_msg_nix_lf_start_rx(mbox_get(mbox));
852 : 0 : rc = mbox_process(mbox);
853 [ # # ]: 0 : if (rc) {
854 : : mbox_put(mbox);
855 : 0 : plt_err("cgx start failed, rc=%d", rc);
856 : 0 : return rc;
857 : : }
858 : : mbox_put(mbox);
859 : : }
860 : :
861 : : /* Disable backpressure */
862 : 0 : rc = nix_tm_bp_config_set(roc_nix, sq->qid, 0, false);
863 [ # # ]: 0 : if (rc) {
864 : 0 : plt_err("Failed to disable backpressure for flush, rc=%d", rc);
865 : 0 : return rc;
866 : : }
867 : :
868 : : /* Disable smq xoff for case it was enabled earlier */
869 : 0 : rc = nix_tm_smq_xoff(nix, node->parent, false);
870 [ # # ]: 0 : if (rc) {
871 : 0 : plt_err("Failed to enable smq %u, rc=%d", node->parent->hw_id,
872 : : rc);
873 : 0 : return rc;
874 : : }
875 : :
876 : : /* As per HRM, to disable an SQ, all other SQ's
877 : : * that feed to same SMQ must be paused before SMQ flush.
878 : : */
879 [ # # ]: 0 : TAILQ_FOREACH(sibling, list, node) {
880 [ # # ]: 0 : if (sibling->parent != node->parent)
881 : 0 : continue;
882 [ # # ]: 0 : if (!(sibling->flags & NIX_TM_NODE_ENABLED))
883 : 0 : continue;
884 : :
885 : 0 : qid = sibling->id;
886 : 0 : sq = nix->sqs[qid];
887 [ # # ]: 0 : if (!sq)
888 : 0 : continue;
889 : :
890 [ # # ]: 0 : if (sq->enable) {
891 : 0 : rc = roc_nix_tm_sq_aura_fc(sq, false);
892 [ # # ]: 0 : if (rc) {
893 : 0 : plt_err("Failed to disable sqb aura fc, rc=%d", rc);
894 : 0 : goto cleanup;
895 : : }
896 : : }
897 : :
898 : : /* Wait for sq entries to be flushed */
899 : 0 : rc = roc_nix_tm_sq_flush_spin(sq);
900 [ # # ]: 0 : if (rc) {
901 [ # # ]: 0 : if (nix->sdp_link)
902 : 0 : rc = nix_tm_sdp_sq_drop_pkts(roc_nix, sq);
903 : : else
904 : 0 : rc = roc_nix_tm_sq_free_pending_sqe(nix, sq->qid);
905 [ # # ]: 0 : if (rc) {
906 : 0 : roc_nix_tm_dump(sq->roc_nix, NULL);
907 : 0 : roc_nix_queues_ctx_dump(sq->roc_nix, NULL);
908 : 0 : plt_err("Failed to drain sq %u, rc=%d\n", sq->qid, rc);
909 : 0 : return rc;
910 : : }
911 : : /* Freed all pending SQEs for this SQ, so disable this node */
912 : 0 : sibling->flags &= ~NIX_TM_NODE_ENABLED;
913 : : }
914 : : }
915 : :
916 : 0 : node->flags &= ~NIX_TM_NODE_ENABLED;
917 : :
918 : : /* Disable and flush */
919 : 0 : rc = nix_tm_smq_xoff(nix, node->parent, true);
920 [ # # ]: 0 : if (rc) {
921 : 0 : plt_err("Failed to disable smq %u, rc=%d", node->parent->hw_id,
922 : : rc);
923 : 0 : goto cleanup;
924 : : }
925 : :
926 : 0 : req = mbox_alloc_msg_nix_rx_sw_sync(mbox_get(mbox));
927 [ # # ]: 0 : if (!req) {
928 : : mbox_put(mbox);
929 : 0 : return -ENOSPC;
930 : : }
931 : :
932 : 0 : rc = mbox_process(mbox);
933 : : mbox_put(mbox);
934 : 0 : cleanup:
935 : : /* Restore cgx state */
936 [ # # ]: 0 : if (!roc_nix->io_enabled) {
937 : 0 : mbox_alloc_msg_nix_lf_stop_rx(mbox_get(mbox));
938 : 0 : rc |= mbox_process(mbox);
939 : : mbox_put(mbox);
940 : : }
941 : :
942 : : return rc;
943 : : }
944 : :
945 : : int
946 : 0 : nix_tm_sq_flush_post(struct roc_nix_sq *sq)
947 : : {
948 [ # # ]: 0 : struct roc_nix *roc_nix = sq->roc_nix;
949 : : struct nix_tm_node *node, *sibling;
950 : : struct nix_tm_node_list *list;
951 : : enum roc_nix_tm_tree tree;
952 : : struct roc_nix_sq *s_sq;
953 : : bool once = false;
954 : : uint16_t qid, s_qid;
955 : : struct nix *nix;
956 : : int rc;
957 : :
958 : : nix = roc_nix_to_nix_priv(roc_nix);
959 : :
960 : : /* Need not do anything if tree is in disabled state */
961 [ # # ]: 0 : if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
962 : : return 0;
963 : :
964 : 0 : qid = sq->qid;
965 : 0 : tree = nix->tm_tree;
966 : : list = nix_tm_node_list(nix, tree);
967 : :
968 : : /* Find the node for this SQ */
969 : 0 : node = nix_tm_node_search(nix, qid, tree);
970 [ # # ]: 0 : if (!node) {
971 : 0 : plt_err("Invalid node for sq %u", qid);
972 : 0 : return -EFAULT;
973 : : }
974 : :
975 : : /* Enable all the siblings back */
976 [ # # ]: 0 : TAILQ_FOREACH(sibling, list, node) {
977 [ # # ]: 0 : if (sibling->parent != node->parent)
978 : 0 : continue;
979 : :
980 [ # # ]: 0 : if (sibling->id == qid)
981 : 0 : continue;
982 : :
983 [ # # ]: 0 : if (!(sibling->flags & NIX_TM_NODE_ENABLED))
984 : 0 : continue;
985 : :
986 : 0 : s_qid = sibling->id;
987 : 0 : s_sq = nix->sqs[s_qid];
988 [ # # ]: 0 : if (!s_sq)
989 : 0 : continue;
990 : :
991 [ # # ]: 0 : if (!once) {
992 : : /* Enable back if any SQ is still present */
993 : 0 : rc = nix_tm_smq_xoff(nix, node->parent, false);
994 [ # # ]: 0 : if (rc) {
995 : 0 : plt_err("Failed to enable smq %u, rc=%d",
996 : : node->parent->hw_id, rc);
997 : 0 : return rc;
998 : : }
999 : : once = true;
1000 : : }
1001 : :
1002 [ # # ]: 0 : if (s_sq->enable) {
1003 : 0 : rc = roc_nix_tm_sq_aura_fc(s_sq, true);
1004 [ # # ]: 0 : if (rc) {
1005 : 0 : plt_err("Failed to enable sqb aura fc, rc=%d", rc);
1006 : 0 : return rc;
1007 : : }
1008 : : }
1009 : : }
1010 : :
1011 : : return 0;
1012 : : }
1013 : :
1014 : : int
1015 : 0 : nix_tm_sq_sched_conf(struct nix *nix, struct nix_tm_node *node,
1016 : : bool rr_quantum_only)
1017 : : {
1018 : 0 : struct mbox *mbox = mbox_get((&nix->dev)->mbox);
1019 : 0 : uint16_t qid = node->id, smq;
1020 : : uint64_t rr_quantum;
1021 : : int rc;
1022 : :
1023 : 0 : smq = node->parent->hw_id;
1024 [ # # ]: 0 : rr_quantum = nix_tm_weight_to_rr_quantum(node->weight);
1025 : :
1026 [ # # ]: 0 : if (rr_quantum_only)
1027 : 0 : plt_tm_dbg("Update sq(%u) rr_quantum 0x%" PRIx64, qid,
1028 : : rr_quantum);
1029 : : else
1030 : 0 : plt_tm_dbg("Enabling sq(%u)->smq(%u), rr_quantum 0x%" PRIx64,
1031 : : qid, smq, rr_quantum);
1032 : :
1033 [ # # ]: 0 : if (qid > nix->nb_tx_queues) {
1034 : : rc = -EFAULT;
1035 : 0 : goto exit;
1036 : : }
1037 : :
1038 [ # # ]: 0 : if (roc_model_is_cn9k()) {
1039 : : struct nix_aq_enq_req *aq;
1040 : :
1041 : 0 : aq = mbox_alloc_msg_nix_aq_enq(mbox);
1042 [ # # ]: 0 : if (!aq) {
1043 : : rc = -ENOSPC;
1044 : 0 : goto exit;
1045 : : }
1046 : :
1047 : 0 : aq->qidx = qid;
1048 : 0 : aq->ctype = NIX_AQ_CTYPE_SQ;
1049 : 0 : aq->op = NIX_AQ_INSTOP_WRITE;
1050 : :
1051 : : /* smq update only when needed */
1052 [ # # ]: 0 : if (!rr_quantum_only) {
1053 : 0 : aq->sq.smq = smq;
1054 : 0 : aq->sq_mask.smq = ~aq->sq_mask.smq;
1055 : : }
1056 : 0 : aq->sq.smq_rr_quantum = rr_quantum;
1057 : 0 : aq->sq_mask.smq_rr_quantum = ~aq->sq_mask.smq_rr_quantum;
1058 : : } else {
1059 : : struct nix_cn10k_aq_enq_req *aq;
1060 : :
1061 : 0 : aq = mbox_alloc_msg_nix_cn10k_aq_enq(mbox);
1062 [ # # ]: 0 : if (!aq) {
1063 : : rc = -ENOSPC;
1064 : 0 : goto exit;
1065 : : }
1066 : :
1067 : 0 : aq->qidx = qid;
1068 : 0 : aq->ctype = NIX_AQ_CTYPE_SQ;
1069 : 0 : aq->op = NIX_AQ_INSTOP_WRITE;
1070 : :
1071 : : /* smq update only when needed */
1072 [ # # ]: 0 : if (!rr_quantum_only) {
1073 : 0 : aq->sq.smq = smq;
1074 : 0 : aq->sq_mask.smq = ~aq->sq_mask.smq;
1075 : : }
1076 : 0 : aq->sq.smq_rr_weight = rr_quantum;
1077 : 0 : aq->sq_mask.smq_rr_weight = ~aq->sq_mask.smq_rr_weight;
1078 : : }
1079 : :
1080 : 0 : rc = mbox_process(mbox);
1081 [ # # ]: 0 : if (rc)
1082 : 0 : plt_err("Failed to set smq, rc=%d", rc);
1083 : 0 : exit:
1084 : : mbox_put(mbox);
1085 : 0 : return rc;
1086 : : }
1087 : :
1088 : : int
1089 : 0 : nix_tm_release_resources(struct nix *nix, uint8_t hw_lvl, bool contig,
1090 : : bool above_thresh)
1091 : : {
1092 : : uint16_t avail, thresh, to_free = 0, schq;
1093 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
1094 : : struct nix_txsch_free_req *req;
1095 : : struct plt_bitmap *bmp;
1096 : 0 : uint64_t slab = 0;
1097 : 0 : uint32_t pos = 0;
1098 : : int rc = -ENOSPC;
1099 : :
1100 [ # # ]: 0 : bmp = contig ? nix->schq_contig_bmp[hw_lvl] : nix->schq_bmp[hw_lvl];
1101 [ # # ]: 0 : thresh =
1102 : 0 : contig ? nix->contig_rsvd[hw_lvl] : nix->discontig_rsvd[hw_lvl];
1103 : : plt_bitmap_scan_init(bmp);
1104 : :
1105 : 0 : avail = nix_tm_resource_avail(nix, hw_lvl, contig);
1106 : :
1107 [ # # ]: 0 : if (above_thresh) {
1108 : : /* Release only above threshold */
1109 [ # # ]: 0 : if (avail > thresh)
1110 : 0 : to_free = avail - thresh;
1111 : : } else {
1112 : : /* Release everything */
1113 : : to_free = avail;
1114 : : }
1115 : :
1116 : : /* Now release resources to AF */
1117 [ # # ]: 0 : while (to_free) {
1118 [ # # # # ]: 0 : if (!slab && !plt_bitmap_scan(bmp, &pos, &slab))
1119 : : break;
1120 : :
1121 [ # # ]: 0 : schq = bitmap_ctzll(slab);
1122 : 0 : slab &= ~(1ULL << schq);
1123 : 0 : schq += pos;
1124 : :
1125 : : /* Free to AF */
1126 : 0 : req = mbox_alloc_msg_nix_txsch_free(mbox_get(mbox));
1127 [ # # ]: 0 : if (req == NULL) {
1128 : : mbox_put(mbox);
1129 : 0 : return rc;
1130 : : }
1131 : 0 : req->flags = 0;
1132 : 0 : req->schq_lvl = hw_lvl;
1133 : 0 : req->schq = schq;
1134 : 0 : rc = mbox_process(mbox);
1135 [ # # ]: 0 : if (rc) {
1136 [ # # # # : 0 : plt_err("failed to release hwres %s(%u) rc %d",
# # ]
1137 : : nix_tm_hwlvl2str(hw_lvl), schq, rc);
1138 : : mbox_put(mbox);
1139 : 0 : return rc;
1140 : : }
1141 : : mbox_put(mbox);
1142 [ # # # # : 0 : plt_tm_dbg("Released hwres %s(%u)", nix_tm_hwlvl2str(hw_lvl),
# # ]
1143 : : schq);
1144 : 0 : plt_bitmap_clear(bmp, schq);
1145 : 0 : to_free--;
1146 : : }
1147 : :
1148 [ # # ]: 0 : if (to_free) {
1149 : 0 : plt_err("resource inconsistency for %s(%u)",
1150 : : nix_tm_hwlvl2str(hw_lvl), contig);
1151 : 0 : return -EFAULT;
1152 : : }
1153 : : return 0;
1154 : : }
1155 : :
1156 : : int
1157 : 0 : nix_tm_free_node_resource(struct nix *nix, struct nix_tm_node *node)
1158 : : {
1159 : 0 : struct mbox *mbox = mbox_get((&nix->dev)->mbox);
1160 : : struct nix_txsch_free_req *req;
1161 : : struct plt_bitmap *bmp;
1162 : : uint16_t avail, hw_id;
1163 : : uint8_t hw_lvl;
1164 : : int rc = -ENOSPC;
1165 : :
1166 : 0 : hw_lvl = node->hw_lvl;
1167 : 0 : hw_id = node->hw_id;
1168 : 0 : bmp = nix->schq_bmp[hw_lvl];
1169 : : /* Free specific HW resource */
1170 [ # # # # : 0 : plt_tm_dbg("Free hwres %s(%u) lvl %u id %u (%p)",
# # ]
1171 : : nix_tm_hwlvl2str(node->hw_lvl), hw_id, node->lvl, node->id,
1172 : : node);
1173 : :
1174 : 0 : avail = nix_tm_resource_avail(nix, hw_lvl, false);
1175 : : /* Always for now free to discontiguous queue when avail
1176 : : * is not sufficient.
1177 : : */
1178 [ # # # # ]: 0 : if (nix->discontig_rsvd[hw_lvl] &&
1179 : : avail < nix->discontig_rsvd[hw_lvl]) {
1180 : : PLT_ASSERT(hw_id < NIX_TM_MAX_HW_TXSCHQ);
1181 : : PLT_ASSERT(plt_bitmap_get(bmp, hw_id) == 0);
1182 : 0 : plt_bitmap_set(bmp, hw_id);
1183 : 0 : node->hw_id = NIX_TM_HW_ID_INVALID;
1184 : 0 : node->flags &= ~NIX_TM_NODE_HWRES;
1185 : : rc = 0;
1186 : 0 : goto exit;
1187 : : }
1188 : :
1189 : : /* Free to AF */
1190 : 0 : req = mbox_alloc_msg_nix_txsch_free(mbox);
1191 [ # # ]: 0 : if (req == NULL)
1192 : 0 : goto exit;
1193 : 0 : req->flags = 0;
1194 : 0 : req->schq_lvl = node->hw_lvl;
1195 : 0 : req->schq = hw_id;
1196 : 0 : rc = mbox_process(mbox);
1197 [ # # ]: 0 : if (rc) {
1198 [ # # # # : 0 : plt_err("failed to release hwres %s(%u) rc %d",
# # ]
1199 : : nix_tm_hwlvl2str(node->hw_lvl), hw_id, rc);
1200 : 0 : goto exit;
1201 : : }
1202 : :
1203 : : /* Mark parent as dirty for reallocing it's children */
1204 [ # # ]: 0 : if (node->parent)
1205 : 0 : node->parent->child_realloc = true;
1206 : :
1207 : 0 : node->hw_id = NIX_TM_HW_ID_INVALID;
1208 : 0 : node->flags &= ~NIX_TM_NODE_HWRES;
1209 [ # # # # : 0 : plt_tm_dbg("Released hwres %s(%u) to af",
# # ]
1210 : : nix_tm_hwlvl2str(node->hw_lvl), hw_id);
1211 : : rc = 0;
1212 : 0 : exit:
1213 : : mbox_put(mbox);
1214 : 0 : return rc;
1215 : : }
1216 : :
1217 : : int
1218 : 0 : nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id,
1219 : : enum roc_nix_tm_tree tree, bool free)
1220 : : {
1221 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1222 : : struct nix_tm_shaper_profile *profile;
1223 : : struct nix_tm_node *node, *child;
1224 : : struct nix_tm_node_list *list;
1225 : : uint32_t profile_id;
1226 : : int rc;
1227 : :
1228 : 0 : plt_tm_dbg("Delete node id %u tree %u", node_id, tree);
1229 : :
1230 : 0 : node = nix_tm_node_search(nix, node_id, tree);
1231 [ # # ]: 0 : if (!node)
1232 : : return NIX_ERR_TM_INVALID_NODE;
1233 : :
1234 : : list = nix_tm_node_list(nix, tree);
1235 : : /* Check for any existing children */
1236 [ # # ]: 0 : TAILQ_FOREACH(child, list, node) {
1237 [ # # ]: 0 : if (child->parent == node)
1238 : : return NIX_ERR_TM_CHILD_EXISTS;
1239 : : }
1240 : :
1241 : : /* Remove shaper profile reference */
1242 : 0 : profile_id = node->shaper_profile_id;
1243 : 0 : profile = nix_tm_shaper_profile_search(nix, profile_id);
1244 : :
1245 : : /* Free hw resource locally */
1246 [ # # ]: 0 : if (node->flags & NIX_TM_NODE_HWRES) {
1247 : 0 : rc = nix_tm_free_node_resource(nix, node);
1248 [ # # ]: 0 : if (rc)
1249 : : return rc;
1250 : : }
1251 : :
1252 [ # # ]: 0 : if (profile)
1253 : 0 : profile->ref_cnt--;
1254 : :
1255 [ # # ]: 0 : TAILQ_REMOVE(list, node, node);
1256 : :
1257 [ # # # # : 0 : plt_tm_dbg("Deleted node %s lvl %u id %u, prio 0x%x weight 0x%x "
# # # # ]
1258 : : "parent %u profile 0x%x tree %u (%p)",
1259 : : nix_tm_hwlvl2str(node->hw_lvl), node->lvl, node->id,
1260 : : node->priority, node->weight,
1261 : : node->parent ? node->parent->id : UINT32_MAX,
1262 : : node->shaper_profile_id, tree, node);
1263 : : /* Free only if requested */
1264 [ # # ]: 0 : if (free)
1265 : 0 : nix_tm_node_free(node);
1266 : : return 0;
1267 : : }
1268 : :
1269 : : static int
1270 : 0 : nix_tm_assign_hw_id(struct nix *nix, struct nix_tm_node *parent,
1271 : : uint16_t *contig_id, int *contig_cnt,
1272 : : struct nix_tm_node_list *list)
1273 : : {
1274 : : struct nix_tm_node *child;
1275 : : struct plt_bitmap *bmp;
1276 : : uint8_t child_hw_lvl;
1277 : : int spare_schq = -1;
1278 : 0 : uint32_t pos = 0;
1279 : : uint64_t slab;
1280 : : uint16_t schq;
1281 : :
1282 : 0 : child_hw_lvl = parent->hw_lvl - 1;
1283 [ # # ]: 0 : bmp = nix->schq_bmp[child_hw_lvl];
1284 : : plt_bitmap_scan_init(bmp);
1285 : 0 : slab = 0;
1286 : :
1287 : : /* Save spare schq if it is case of RR + SP */
1288 [ # # # # ]: 0 : if (parent->rr_prio != 0xf && *contig_cnt > 1)
1289 : 0 : spare_schq = *contig_id + parent->rr_prio;
1290 : :
1291 [ # # ]: 0 : TAILQ_FOREACH(child, list, node) {
1292 [ # # ]: 0 : if (!child->parent)
1293 : 0 : continue;
1294 [ # # ]: 0 : if (child->parent->id != parent->id)
1295 : 0 : continue;
1296 : :
1297 : : /* Resource never expected to be present */
1298 [ # # ]: 0 : if (child->flags & NIX_TM_NODE_HWRES) {
1299 [ # # # # : 0 : plt_err("Resource exists for child (%s)%u, id %u (%p)",
# # ]
1300 : : nix_tm_hwlvl2str(child->hw_lvl), child->hw_id,
1301 : : child->id, child);
1302 : 0 : return -EFAULT;
1303 : : }
1304 : :
1305 [ # # ]: 0 : if (!slab)
1306 : 0 : plt_bitmap_scan(bmp, &pos, &slab);
1307 : :
1308 [ # # # # ]: 0 : if (child->priority == parent->rr_prio && spare_schq != -1) {
1309 : : /* Use spare schq first if present */
1310 : 0 : schq = spare_schq;
1311 : : spare_schq = -1;
1312 : 0 : *contig_cnt = *contig_cnt - 1;
1313 : :
1314 [ # # ]: 0 : } else if (child->priority == parent->rr_prio) {
1315 : : /* Assign a discontiguous queue */
1316 [ # # ]: 0 : if (!slab) {
1317 : 0 : plt_err("Schq not found for Child %u "
1318 : : "lvl %u (%p)",
1319 : : child->id, child->lvl, child);
1320 : 0 : return -ENOENT;
1321 : : }
1322 : :
1323 : 0 : schq = bitmap_ctzll(slab);
1324 : 0 : slab &= ~(1ULL << schq);
1325 : 0 : schq += pos;
1326 : 0 : plt_bitmap_clear(bmp, schq);
1327 : : } else {
1328 : : /* Assign a contiguous queue */
1329 : 0 : schq = *contig_id + child->priority;
1330 : 0 : *contig_cnt = *contig_cnt - 1;
1331 : : }
1332 : :
1333 [ # # # # : 0 : plt_tm_dbg("Resource %s(%u), for lvl %u id %u(%p)",
# # ]
1334 : : nix_tm_hwlvl2str(child->hw_lvl), schq, child->lvl,
1335 : : child->id, child);
1336 : :
1337 : 0 : child->hw_id = schq;
1338 : 0 : child->parent_hw_id = parent->hw_id;
1339 : 0 : child->flags |= NIX_TM_NODE_HWRES;
1340 : : }
1341 : :
1342 : : return 0;
1343 : : }
1344 : :
1345 : : int
1346 : 0 : nix_tm_assign_resources(struct nix *nix, enum roc_nix_tm_tree tree)
1347 : : {
1348 : : struct nix_tm_node *parent, *root = NULL;
1349 : : struct plt_bitmap *bmp, *bmp_contig;
1350 : : struct nix_tm_node_list *list;
1351 : : uint8_t child_hw_lvl, hw_lvl;
1352 : : uint16_t contig_id, j;
1353 : 0 : uint64_t slab = 0;
1354 : 0 : uint32_t pos = 0;
1355 : : int cnt, rc;
1356 : :
1357 : : list = nix_tm_node_list(nix, tree);
1358 : : /* Walk from TL1 to TL4 parents */
1359 [ # # ]: 0 : for (hw_lvl = NIX_TXSCH_LVL_TL1; hw_lvl > 0; hw_lvl--) {
1360 [ # # ]: 0 : TAILQ_FOREACH(parent, list, node) {
1361 : 0 : child_hw_lvl = parent->hw_lvl - 1;
1362 [ # # ]: 0 : if (parent->hw_lvl != hw_lvl)
1363 : 0 : continue;
1364 : :
1365 : : /* Remember root for future */
1366 [ # # ]: 0 : if (parent->hw_lvl == nix->tm_root_lvl)
1367 : : root = parent;
1368 : :
1369 [ # # ]: 0 : if (!parent->child_realloc) {
1370 : : /* Skip when parent is not dirty */
1371 [ # # ]: 0 : if (nix_tm_child_res_valid(list, parent))
1372 : 0 : continue;
1373 : 0 : plt_err("Parent not dirty but invalid "
1374 : : "child res parent id %u(lvl %u)",
1375 : : parent->id, parent->lvl);
1376 : 0 : return -EFAULT;
1377 : : }
1378 : :
1379 : 0 : bmp_contig = nix->schq_contig_bmp[child_hw_lvl];
1380 : :
1381 : : /* Prealloc contiguous indices for a parent */
1382 : 0 : contig_id = NIX_TM_MAX_HW_TXSCHQ;
1383 : 0 : cnt = (int)parent->max_prio + 1;
1384 [ # # ]: 0 : if (cnt > 0) {
1385 : : plt_bitmap_scan_init(bmp_contig);
1386 [ # # ]: 0 : if (!plt_bitmap_scan(bmp_contig, &pos, &slab)) {
1387 : 0 : plt_err("Contig schq not found");
1388 : 0 : return -ENOENT;
1389 : : }
1390 [ # # ]: 0 : contig_id = pos + bitmap_ctzll(slab);
1391 : :
1392 : : /* Check if we have enough */
1393 [ # # ]: 0 : for (j = contig_id; j < contig_id + cnt; j++) {
1394 [ # # ]: 0 : if (!plt_bitmap_get(bmp_contig, j))
1395 : : break;
1396 : : }
1397 : :
1398 [ # # ]: 0 : if (j != contig_id + cnt) {
1399 : 0 : plt_err("Contig schq not sufficient");
1400 : 0 : return -ENOENT;
1401 : : }
1402 : :
1403 [ # # ]: 0 : for (j = contig_id; j < contig_id + cnt; j++)
1404 : 0 : plt_bitmap_clear(bmp_contig, j);
1405 : : }
1406 : :
1407 : : /* Assign hw id to all children */
1408 : 0 : rc = nix_tm_assign_hw_id(nix, parent, &contig_id, &cnt,
1409 : : list);
1410 [ # # ]: 0 : if (cnt || rc) {
1411 : 0 : plt_err("Unexpected err, contig res alloc, "
1412 : : "parent %u, of %s, rc=%d, cnt=%d",
1413 : : parent->id, nix_tm_hwlvl2str(hw_lvl),
1414 : : rc, cnt);
1415 : 0 : return -EFAULT;
1416 : : }
1417 : :
1418 : : /* Clear the dirty bit as children's
1419 : : * resources are reallocated.
1420 : : */
1421 : 0 : parent->child_realloc = false;
1422 : : }
1423 : : }
1424 : :
1425 : : /* Root is always expected to be there */
1426 [ # # ]: 0 : if (!root)
1427 : : return -EFAULT;
1428 : :
1429 [ # # ]: 0 : if (root->flags & NIX_TM_NODE_HWRES)
1430 : : return 0;
1431 : :
1432 : : /* Process root node */
1433 : 0 : bmp = nix->schq_bmp[nix->tm_root_lvl];
1434 : : plt_bitmap_scan_init(bmp);
1435 [ # # ]: 0 : if (!plt_bitmap_scan(bmp, &pos, &slab)) {
1436 : 0 : plt_err("Resource not allocated for root");
1437 : 0 : return -EIO;
1438 : : }
1439 : :
1440 [ # # ]: 0 : root->hw_id = pos + bitmap_ctzll(slab);
1441 : 0 : root->flags |= NIX_TM_NODE_HWRES;
1442 : 0 : plt_bitmap_clear(bmp, root->hw_id);
1443 : :
1444 : : /* Get TL1 id as well when root is not TL1 */
1445 [ # # ]: 0 : if (!nix_tm_have_tl1_access(nix)) {
1446 : 0 : bmp = nix->schq_bmp[NIX_TXSCH_LVL_TL1];
1447 : :
1448 : : plt_bitmap_scan_init(bmp);
1449 [ # # ]: 0 : if (!plt_bitmap_scan(bmp, &pos, &slab)) {
1450 : 0 : plt_err("Resource not found for TL1");
1451 : 0 : return -EIO;
1452 : : }
1453 [ # # ]: 0 : root->parent_hw_id = pos + bitmap_ctzll(slab);
1454 : 0 : plt_bitmap_clear(bmp, root->parent_hw_id);
1455 : : }
1456 : :
1457 [ # # # # : 0 : plt_tm_dbg("Resource %s(%u) for root(id %u) (%p)",
# # ]
1458 : : nix_tm_hwlvl2str(root->hw_lvl), root->hw_id, root->id, root);
1459 : :
1460 : 0 : return 0;
1461 : : }
1462 : :
1463 : : void
1464 : 0 : nix_tm_copy_rsp_to_nix(struct nix *nix, struct nix_txsch_alloc_rsp *rsp)
1465 : : {
1466 : : uint8_t lvl;
1467 : : uint16_t i;
1468 : :
1469 [ # # ]: 0 : for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
1470 [ # # ]: 0 : for (i = 0; i < rsp->schq[lvl]; i++)
1471 : 0 : plt_bitmap_set(nix->schq_bmp[lvl],
1472 : 0 : rsp->schq_list[lvl][i]);
1473 : :
1474 [ # # ]: 0 : for (i = 0; i < rsp->schq_contig[lvl]; i++)
1475 : 0 : plt_bitmap_set(nix->schq_contig_bmp[lvl],
1476 : 0 : rsp->schq_contig_list[lvl][i]);
1477 : : }
1478 : 0 : }
1479 : :
1480 : : int
1481 : 0 : nix_tm_alloc_txschq(struct nix *nix, enum roc_nix_tm_tree tree)
1482 : : {
1483 : : uint16_t schq_contig[NIX_TXSCH_LVL_CNT];
1484 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
1485 : : uint16_t schq[NIX_TXSCH_LVL_CNT];
1486 : : struct nix_txsch_alloc_req *req;
1487 : : struct nix_txsch_alloc_rsp *rsp;
1488 : : uint8_t hw_lvl, i;
1489 : : bool pend;
1490 : : int rc;
1491 : :
1492 : : memset(schq, 0, sizeof(schq));
1493 : : memset(schq_contig, 0, sizeof(schq_contig));
1494 : :
1495 : : /* Estimate requirement */
1496 : 0 : rc = nix_tm_resource_estimate(nix, schq_contig, schq, tree);
1497 [ # # ]: 0 : if (!rc)
1498 : : return 0;
1499 : :
1500 : : /* Release existing contiguous resources when realloc requested
1501 : : * as there is no way to guarantee continuity of old with new.
1502 : : */
1503 [ # # ]: 0 : for (hw_lvl = 0; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
1504 [ # # ]: 0 : if (schq_contig[hw_lvl])
1505 : 0 : nix_tm_release_resources(nix, hw_lvl, true, false);
1506 : : }
1507 : :
1508 : : /* Alloc as needed */
1509 : : do {
1510 : : pend = false;
1511 : 0 : req = mbox_alloc_msg_nix_txsch_alloc(mbox_get(mbox));
1512 [ # # ]: 0 : if (!req) {
1513 : : mbox_put(mbox);
1514 : : rc = -ENOMEM;
1515 : 0 : goto alloc_err;
1516 : : }
1517 : 0 : mbox_memcpy(req->schq, schq, sizeof(req->schq));
1518 : 0 : mbox_memcpy(req->schq_contig, schq_contig,
1519 : : sizeof(req->schq_contig));
1520 : :
1521 : : /* Each alloc can be at max of MAX_TXSCHQ_PER_FUNC per level.
1522 : : * So split alloc to multiple requests.
1523 : : */
1524 [ # # ]: 0 : for (i = 0; i < NIX_TXSCH_LVL_CNT; i++) {
1525 [ # # ]: 0 : if (req->schq[i] > MAX_TXSCHQ_PER_FUNC)
1526 : 0 : req->schq[i] = MAX_TXSCHQ_PER_FUNC;
1527 : 0 : schq[i] -= req->schq[i];
1528 : :
1529 [ # # ]: 0 : if (req->schq_contig[i] > MAX_TXSCHQ_PER_FUNC)
1530 : 0 : req->schq_contig[i] = MAX_TXSCHQ_PER_FUNC;
1531 : 0 : schq_contig[i] -= req->schq_contig[i];
1532 : :
1533 [ # # # # ]: 0 : if (schq[i] || schq_contig[i])
1534 : : pend = true;
1535 : : }
1536 : :
1537 : : rc = mbox_process_msg(mbox, (void *)&rsp);
1538 [ # # ]: 0 : if (rc) {
1539 : : mbox_put(mbox);
1540 : 0 : goto alloc_err;
1541 : : }
1542 : :
1543 : 0 : nix_tm_copy_rsp_to_nix(nix, rsp);
1544 : : mbox_put(mbox);
1545 [ # # ]: 0 : } while (pend);
1546 : :
1547 : 0 : nix->tm_link_cfg_lvl = rsp->link_cfg_lvl;
1548 : 0 : nix->tm_aggr_lvl_rr_prio = rsp->aggr_lvl_rr_prio;
1549 : 0 : return 0;
1550 : 0 : alloc_err:
1551 [ # # ]: 0 : for (i = 0; i < NIX_TXSCH_LVL_CNT; i++) {
1552 [ # # ]: 0 : if (nix_tm_release_resources(nix, i, true, false))
1553 : 0 : plt_err("Failed to release contig resources of "
1554 : : "lvl %d on error",
1555 : : i);
1556 [ # # ]: 0 : if (nix_tm_release_resources(nix, i, false, false))
1557 : 0 : plt_err("Failed to release discontig resources of "
1558 : : "lvl %d on error",
1559 : : i);
1560 : : }
1561 : : return rc;
1562 : : }
1563 : :
1564 : : int
1565 : 0 : nix_tm_prepare_default_tree(struct roc_nix *roc_nix)
1566 : : {
1567 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1568 [ # # ]: 0 : uint32_t nonleaf_id = nix->nb_tx_queues;
1569 : : struct nix_tm_node *node = NULL;
1570 : : uint8_t leaf_lvl, lvl, lvl_end;
1571 : : uint32_t parent, i;
1572 : : int rc = 0;
1573 : :
1574 : : /* Add ROOT, SCH1, SCH2, SCH3, [SCH4] nodes */
1575 : : parent = ROC_NIX_TM_NODE_ID_INVALID;
1576 : : /* With TL1 access we have an extra level */
1577 [ # # ]: 0 : lvl_end = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH4 :
1578 : : ROC_TM_LVL_SCH3);
1579 : :
1580 [ # # ]: 0 : for (lvl = ROC_TM_LVL_ROOT; lvl <= lvl_end; lvl++) {
1581 : : rc = -ENOMEM;
1582 : 0 : node = nix_tm_node_alloc();
1583 [ # # ]: 0 : if (!node)
1584 : 0 : goto error;
1585 : :
1586 : 0 : node->id = nonleaf_id;
1587 : 0 : node->parent_id = parent;
1588 : 0 : node->priority = 0;
1589 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1590 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1591 : 0 : node->lvl = lvl;
1592 : 0 : node->tree = ROC_NIX_TM_DEFAULT;
1593 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1594 : :
1595 : 0 : rc = nix_tm_node_add(roc_nix, node);
1596 [ # # ]: 0 : if (rc)
1597 : 0 : goto error;
1598 : : parent = nonleaf_id;
1599 : 0 : nonleaf_id++;
1600 : : }
1601 : :
1602 [ # # ]: 0 : parent = nonleaf_id - 1;
1603 [ # # ]: 0 : leaf_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_QUEUE :
1604 : : ROC_TM_LVL_SCH4);
1605 : :
1606 : : /* Add leaf nodes */
1607 [ # # ]: 0 : for (i = 0; i < nix->nb_tx_queues; i++) {
1608 : : rc = -ENOMEM;
1609 : 0 : node = nix_tm_node_alloc();
1610 [ # # ]: 0 : if (!node)
1611 : 0 : goto error;
1612 : :
1613 : 0 : node->id = i;
1614 : 0 : node->parent_id = parent;
1615 : 0 : node->priority = 0;
1616 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1617 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1618 : 0 : node->lvl = leaf_lvl;
1619 : 0 : node->tree = ROC_NIX_TM_DEFAULT;
1620 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1621 : :
1622 : 0 : rc = nix_tm_node_add(roc_nix, node);
1623 [ # # ]: 0 : if (rc)
1624 : 0 : goto error;
1625 : : }
1626 : :
1627 : : return 0;
1628 : 0 : error:
1629 : 0 : nix_tm_node_free(node);
1630 : 0 : return rc;
1631 : : }
1632 : :
1633 : : int
1634 : 0 : roc_nix_tm_prepare_rate_limited_tree(struct roc_nix *roc_nix)
1635 : : {
1636 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1637 [ # # ]: 0 : uint32_t nonleaf_id = nix->nb_tx_queues;
1638 : : struct nix_tm_node *node = NULL;
1639 : : uint8_t leaf_lvl, lvl, lvl_end;
1640 : : uint32_t parent, i;
1641 : : int rc = 0;
1642 : :
1643 : : /* Add ROOT, SCH1, SCH2 nodes */
1644 : : parent = ROC_NIX_TM_NODE_ID_INVALID;
1645 [ # # ]: 0 : lvl_end = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH3 :
1646 : : ROC_TM_LVL_SCH2);
1647 : :
1648 [ # # ]: 0 : for (lvl = ROC_TM_LVL_ROOT; lvl <= lvl_end; lvl++) {
1649 : : rc = -ENOMEM;
1650 : 0 : node = nix_tm_node_alloc();
1651 [ # # ]: 0 : if (!node)
1652 : 0 : goto error;
1653 : :
1654 : 0 : node->id = nonleaf_id;
1655 : 0 : node->parent_id = parent;
1656 : 0 : node->priority = 0;
1657 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1658 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1659 : 0 : node->lvl = lvl;
1660 : 0 : node->tree = ROC_NIX_TM_RLIMIT;
1661 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1662 : :
1663 : 0 : rc = nix_tm_node_add(roc_nix, node);
1664 [ # # ]: 0 : if (rc)
1665 : 0 : goto error;
1666 : : parent = nonleaf_id;
1667 : 0 : nonleaf_id++;
1668 : : }
1669 : :
1670 : : /* SMQ is mapped to SCH4 when we have TL1 access and SCH3 otherwise */
1671 [ # # ]: 0 : lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH4 : ROC_TM_LVL_SCH3);
1672 : :
1673 : : /* Add per queue SMQ nodes i.e SCH4 / SCH3 */
1674 [ # # ]: 0 : for (i = 0; i < nix->nb_tx_queues; i++) {
1675 : : rc = -ENOMEM;
1676 : 0 : node = nix_tm_node_alloc();
1677 [ # # ]: 0 : if (!node)
1678 : 0 : goto error;
1679 : :
1680 : 0 : node->id = nonleaf_id + i;
1681 : 0 : node->parent_id = parent;
1682 : 0 : node->priority = 0;
1683 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1684 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1685 : 0 : node->lvl = lvl;
1686 : 0 : node->tree = ROC_NIX_TM_RLIMIT;
1687 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1688 : :
1689 : 0 : rc = nix_tm_node_add(roc_nix, node);
1690 [ # # ]: 0 : if (rc)
1691 : 0 : goto error;
1692 : : }
1693 : :
1694 : : parent = nonleaf_id;
1695 [ # # ]: 0 : leaf_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_QUEUE :
1696 : : ROC_TM_LVL_SCH4);
1697 : :
1698 : : /* Add leaf nodes */
1699 [ # # ]: 0 : for (i = 0; i < nix->nb_tx_queues; i++) {
1700 : : rc = -ENOMEM;
1701 : 0 : node = nix_tm_node_alloc();
1702 [ # # ]: 0 : if (!node)
1703 : 0 : goto error;
1704 : :
1705 : 0 : node->id = i;
1706 : 0 : node->parent_id = parent + i;
1707 : 0 : node->priority = 0;
1708 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1709 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1710 : 0 : node->lvl = leaf_lvl;
1711 : 0 : node->tree = ROC_NIX_TM_RLIMIT;
1712 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1713 : :
1714 : 0 : rc = nix_tm_node_add(roc_nix, node);
1715 [ # # ]: 0 : if (rc)
1716 : 0 : goto error;
1717 : : }
1718 : :
1719 : : return 0;
1720 : 0 : error:
1721 : 0 : nix_tm_node_free(node);
1722 : 0 : return rc;
1723 : : }
1724 : :
1725 : : int
1726 : 0 : roc_nix_tm_pfc_prepare_tree(struct roc_nix *roc_nix)
1727 : : {
1728 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1729 : : uint8_t leaf_lvl, lvl, lvl_start, lvl_end;
1730 [ # # ]: 0 : uint32_t nonleaf_id = nix->nb_tx_queues;
1731 : : struct nix_tm_node *node = NULL;
1732 : : uint32_t tl2_node_id;
1733 : : uint32_t parent, i;
1734 : : int rc = -ENOMEM;
1735 : :
1736 : : parent = ROC_NIX_TM_NODE_ID_INVALID;
1737 [ # # ]: 0 : lvl_end = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH3 :
1738 : : ROC_TM_LVL_SCH2);
1739 [ # # ]: 0 : leaf_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_QUEUE :
1740 : : ROC_TM_LVL_SCH4);
1741 : :
1742 : : /* TL1 node */
1743 : 0 : node = nix_tm_node_alloc();
1744 [ # # ]: 0 : if (!node)
1745 : 0 : goto error;
1746 : :
1747 : 0 : node->id = nonleaf_id;
1748 : 0 : node->parent_id = parent;
1749 : 0 : node->priority = 0;
1750 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1751 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1752 : 0 : node->lvl = ROC_TM_LVL_ROOT;
1753 : 0 : node->tree = ROC_NIX_TM_PFC;
1754 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1755 : :
1756 : 0 : rc = nix_tm_node_add(roc_nix, node);
1757 [ # # ]: 0 : if (rc)
1758 : 0 : goto error;
1759 : :
1760 : : parent = nonleaf_id;
1761 : 0 : nonleaf_id++;
1762 : :
1763 : : lvl_start = ROC_TM_LVL_SCH1;
1764 [ # # ]: 0 : if (roc_nix_is_pf(roc_nix)) {
1765 : : /* TL2 node */
1766 : : rc = -ENOMEM;
1767 : 0 : node = nix_tm_node_alloc();
1768 [ # # ]: 0 : if (!node)
1769 : 0 : goto error;
1770 : :
1771 : 0 : node->id = nonleaf_id;
1772 : 0 : node->parent_id = parent;
1773 : 0 : node->priority = 0;
1774 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1775 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1776 : 0 : node->lvl = ROC_TM_LVL_SCH1;
1777 : 0 : node->tree = ROC_NIX_TM_PFC;
1778 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1779 : :
1780 : 0 : rc = nix_tm_node_add(roc_nix, node);
1781 [ # # ]: 0 : if (rc)
1782 : 0 : goto error;
1783 : :
1784 : : lvl_start = ROC_TM_LVL_SCH2;
1785 : : tl2_node_id = nonleaf_id;
1786 : 0 : nonleaf_id++;
1787 : : } else {
1788 : : tl2_node_id = parent;
1789 : : }
1790 : :
1791 [ # # ]: 0 : for (i = 0; i < nix->nb_tx_queues; i++) {
1792 : : parent = tl2_node_id;
1793 [ # # ]: 0 : for (lvl = lvl_start; lvl <= lvl_end; lvl++) {
1794 : : rc = -ENOMEM;
1795 : 0 : node = nix_tm_node_alloc();
1796 [ # # ]: 0 : if (!node)
1797 : 0 : goto error;
1798 : :
1799 : 0 : node->id = nonleaf_id;
1800 : 0 : node->parent_id = parent;
1801 : 0 : node->priority = 0;
1802 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1803 : 0 : node->shaper_profile_id =
1804 : : ROC_NIX_TM_SHAPER_PROFILE_NONE;
1805 : 0 : node->lvl = lvl;
1806 : 0 : node->tree = ROC_NIX_TM_PFC;
1807 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1808 : :
1809 : 0 : rc = nix_tm_node_add(roc_nix, node);
1810 [ # # ]: 0 : if (rc)
1811 : 0 : goto error;
1812 : :
1813 : : parent = nonleaf_id;
1814 : 0 : nonleaf_id++;
1815 : : }
1816 : :
1817 [ # # ]: 0 : lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH4 :
1818 : : ROC_TM_LVL_SCH3);
1819 : :
1820 : : rc = -ENOMEM;
1821 : 0 : node = nix_tm_node_alloc();
1822 [ # # ]: 0 : if (!node)
1823 : 0 : goto error;
1824 : :
1825 : 0 : node->id = nonleaf_id;
1826 : 0 : node->parent_id = parent;
1827 : 0 : node->priority = 0;
1828 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1829 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1830 : 0 : node->lvl = lvl;
1831 : 0 : node->tree = ROC_NIX_TM_PFC;
1832 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1833 : :
1834 : 0 : rc = nix_tm_node_add(roc_nix, node);
1835 [ # # ]: 0 : if (rc)
1836 : 0 : goto error;
1837 : :
1838 : : parent = nonleaf_id;
1839 : 0 : nonleaf_id++;
1840 : :
1841 : : rc = -ENOMEM;
1842 : 0 : node = nix_tm_node_alloc();
1843 [ # # ]: 0 : if (!node)
1844 : 0 : goto error;
1845 : :
1846 : 0 : node->id = i;
1847 : 0 : node->parent_id = parent;
1848 : 0 : node->priority = 0;
1849 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1850 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1851 : 0 : node->lvl = leaf_lvl;
1852 : 0 : node->tree = ROC_NIX_TM_PFC;
1853 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1854 : :
1855 : 0 : rc = nix_tm_node_add(roc_nix, node);
1856 [ # # ]: 0 : if (rc)
1857 : 0 : goto error;
1858 : : }
1859 : :
1860 : : return 0;
1861 : 0 : error:
1862 : 0 : nix_tm_node_free(node);
1863 : 0 : return rc;
1864 : : }
1865 : :
1866 : : int
1867 : 0 : nix_tm_free_resources(struct roc_nix *roc_nix, uint32_t tree_mask, bool hw_only)
1868 : : {
1869 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1870 : : struct nix_tm_shaper_profile *profile;
1871 : : struct nix_tm_node *node, *next_node;
1872 : : struct nix_tm_node_list *list;
1873 : : enum roc_nix_tm_tree tree;
1874 : : uint32_t profile_id;
1875 : : int rc = 0;
1876 : : int hw_lvl;
1877 : :
1878 [ # # ]: 0 : for (tree = 0; tree < ROC_NIX_TM_TREE_MAX; tree++) {
1879 [ # # ]: 0 : if (!(tree_mask & BIT(tree)))
1880 : 0 : continue;
1881 : :
1882 : 0 : plt_tm_dbg("Freeing resources of tree %u", tree);
1883 : :
1884 : : list = nix_tm_node_list(nix, tree);
1885 : : /* Flush and free resources from leaf */
1886 [ # # ]: 0 : for (hw_lvl = NIX_TXSCH_LVL_SMQ; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
1887 : 0 : next_node = TAILQ_FIRST(list);
1888 [ # # ]: 0 : while (next_node) {
1889 : : node = next_node;
1890 : 0 : next_node = TAILQ_NEXT(node, node);
1891 [ # # ]: 0 : if (node->hw_lvl != hw_lvl)
1892 : 0 : continue;
1893 : :
1894 [ # # # # ]: 0 : if (!nix_tm_is_leaf(nix, node->lvl) &&
1895 [ # # ]: 0 : node->flags & NIX_TM_NODE_HWRES) {
1896 : : /* Clear xoff in path for flush to succeed */
1897 : 0 : rc = nix_tm_clear_path_xoff(nix, node);
1898 [ # # ]: 0 : if (rc)
1899 : 0 : return rc;
1900 : 0 : rc = nix_tm_free_node_resource(nix, node);
1901 [ # # ]: 0 : if (rc)
1902 : 0 : return rc;
1903 : : }
1904 : : }
1905 : : }
1906 : :
1907 : : /* Leave software elements if needed */
1908 [ # # ]: 0 : if (hw_only)
1909 : 0 : continue;
1910 : :
1911 : 0 : next_node = TAILQ_FIRST(list);
1912 [ # # ]: 0 : while (next_node) {
1913 : : node = next_node;
1914 : 0 : next_node = TAILQ_NEXT(node, node);
1915 : :
1916 : 0 : plt_tm_dbg("Free node lvl %u id %u (%p)", node->lvl,
1917 : : node->id, node);
1918 : :
1919 : 0 : profile_id = node->shaper_profile_id;
1920 : 0 : profile = nix_tm_shaper_profile_search(nix, profile_id);
1921 [ # # ]: 0 : if (profile)
1922 : 0 : profile->ref_cnt--;
1923 : :
1924 [ # # ]: 0 : TAILQ_REMOVE(list, node, node);
1925 : 0 : nix_tm_node_free(node);
1926 : : }
1927 : : }
1928 : : return rc;
1929 : : }
1930 : :
1931 : : int
1932 : 0 : nix_tm_conf_init(struct roc_nix *roc_nix)
1933 : : {
1934 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1935 : : uint32_t bmp_sz, hw_lvl;
1936 : : void *bmp_mem;
1937 : : int rc, i;
1938 : :
1939 : : PLT_STATIC_ASSERT(sizeof(struct nix_tm_node) <= ROC_NIX_TM_NODE_SZ);
1940 : : PLT_STATIC_ASSERT(sizeof(struct nix_tm_shaper_profile) <=
1941 : : ROC_NIX_TM_SHAPER_PROFILE_SZ);
1942 : :
1943 : 0 : nix->tm_flags = 0;
1944 [ # # ]: 0 : for (i = 0; i < ROC_NIX_TM_TREE_MAX; i++)
1945 : 0 : TAILQ_INIT(&nix->trees[i]);
1946 : :
1947 : 0 : TAILQ_INIT(&nix->shaper_profile_list);
1948 : 0 : nix->tm_rate_min = 1E9; /* 1Gbps */
1949 : :
1950 : : rc = -ENOMEM;
1951 : : bmp_sz = plt_bitmap_get_memory_footprint(NIX_TM_MAX_HW_TXSCHQ);
1952 : 0 : bmp_mem = plt_zmalloc(bmp_sz * NIX_TXSCH_LVL_CNT * 2, 0);
1953 [ # # ]: 0 : if (!bmp_mem)
1954 : : return rc;
1955 : 0 : nix->schq_bmp_mem = bmp_mem;
1956 : :
1957 : : /* Init contiguous and discontiguous bitmap per lvl */
1958 : : rc = -EIO;
1959 [ # # ]: 0 : for (hw_lvl = 0; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
1960 : : /* Bitmap for discontiguous resource */
1961 : 0 : nix->schq_bmp[hw_lvl] =
1962 : 0 : plt_bitmap_init(NIX_TM_MAX_HW_TXSCHQ, bmp_mem, bmp_sz);
1963 [ # # ]: 0 : if (!nix->schq_bmp[hw_lvl])
1964 : 0 : goto exit;
1965 : :
1966 : 0 : bmp_mem = PLT_PTR_ADD(bmp_mem, bmp_sz);
1967 : :
1968 : : /* Bitmap for contiguous resource */
1969 : 0 : nix->schq_contig_bmp[hw_lvl] =
1970 : 0 : plt_bitmap_init(NIX_TM_MAX_HW_TXSCHQ, bmp_mem, bmp_sz);
1971 [ # # ]: 0 : if (!nix->schq_contig_bmp[hw_lvl])
1972 : 0 : goto exit;
1973 : :
1974 : 0 : bmp_mem = PLT_PTR_ADD(bmp_mem, bmp_sz);
1975 : : }
1976 : :
1977 : 0 : rc = nix_tm_mark_init(nix);
1978 [ # # ]: 0 : if (rc)
1979 : 0 : goto exit;
1980 : :
1981 : : /* Disable TL1 Static Priority when VF's are enabled
1982 : : * as otherwise VF's TL2 reallocation will be needed
1983 : : * runtime to support a specific topology of PF.
1984 : : */
1985 [ # # ]: 0 : if (nix->pci_dev->max_vfs)
1986 : 0 : nix->tm_flags |= NIX_TM_TL1_NO_SP;
1987 : :
1988 : : /* TL1 access is only for PF's */
1989 [ # # ]: 0 : if (roc_nix_is_pf(roc_nix)) {
1990 : 0 : nix->tm_flags |= NIX_TM_TL1_ACCESS;
1991 : 0 : nix->tm_root_lvl = NIX_TXSCH_LVL_TL1;
1992 : : } else {
1993 : 0 : nix->tm_root_lvl = NIX_TXSCH_LVL_TL2;
1994 : : }
1995 : :
1996 : : return 0;
1997 : 0 : exit:
1998 : 0 : nix_tm_conf_fini(roc_nix);
1999 : 0 : return rc;
2000 : : }
2001 : :
2002 : : void
2003 : 0 : nix_tm_conf_fini(struct roc_nix *roc_nix)
2004 : : {
2005 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
2006 : : uint16_t hw_lvl;
2007 : :
2008 : : for (hw_lvl = 0; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
2009 : : plt_bitmap_free(nix->schq_bmp[hw_lvl]);
2010 : : plt_bitmap_free(nix->schq_contig_bmp[hw_lvl]);
2011 : : }
2012 : 0 : plt_free(nix->schq_bmp_mem);
2013 : 0 : }
|