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 : rc = roc_nix_tm_sq_aura_fc(sq, false);
891 [ # # ]: 0 : if (rc) {
892 : 0 : plt_err("Failed to disable sqb aura fc, rc=%d", rc);
893 : 0 : goto cleanup;
894 : : }
895 : :
896 : : /* Wait for sq entries to be flushed */
897 : 0 : rc = roc_nix_tm_sq_flush_spin(sq);
898 [ # # ]: 0 : if (rc) {
899 [ # # ]: 0 : if (nix->sdp_link)
900 : 0 : rc = nix_tm_sdp_sq_drop_pkts(roc_nix, sq);
901 : : else
902 : 0 : rc = roc_nix_tm_sq_free_pending_sqe(nix, sq->qid);
903 [ # # ]: 0 : if (rc) {
904 : 0 : roc_nix_tm_dump(sq->roc_nix, NULL);
905 : 0 : roc_nix_queues_ctx_dump(sq->roc_nix, NULL);
906 : 0 : plt_err("Failed to drain sq %u, rc=%d\n", sq->qid, rc);
907 : 0 : return rc;
908 : : }
909 : : /* Freed all pending SQEs for this SQ, so disable this node */
910 : 0 : sibling->flags &= ~NIX_TM_NODE_ENABLED;
911 : : }
912 : : }
913 : :
914 : 0 : node->flags &= ~NIX_TM_NODE_ENABLED;
915 : :
916 : : /* Disable and flush */
917 : 0 : rc = nix_tm_smq_xoff(nix, node->parent, true);
918 [ # # ]: 0 : if (rc) {
919 : 0 : plt_err("Failed to disable smq %u, rc=%d", node->parent->hw_id,
920 : : rc);
921 : 0 : goto cleanup;
922 : : }
923 : :
924 : 0 : req = mbox_alloc_msg_nix_rx_sw_sync(mbox_get(mbox));
925 [ # # ]: 0 : if (!req) {
926 : : mbox_put(mbox);
927 : 0 : return -ENOSPC;
928 : : }
929 : :
930 : 0 : rc = mbox_process(mbox);
931 : : mbox_put(mbox);
932 : 0 : cleanup:
933 : : /* Restore cgx state */
934 [ # # ]: 0 : if (!roc_nix->io_enabled) {
935 : 0 : mbox_alloc_msg_nix_lf_stop_rx(mbox_get(mbox));
936 : 0 : rc |= mbox_process(mbox);
937 : : mbox_put(mbox);
938 : : }
939 : :
940 : : return rc;
941 : : }
942 : :
943 : : int
944 : 0 : nix_tm_sq_flush_post(struct roc_nix_sq *sq)
945 : : {
946 [ # # ]: 0 : struct roc_nix *roc_nix = sq->roc_nix;
947 : : struct nix_tm_node *node, *sibling;
948 : : struct nix_tm_node_list *list;
949 : : enum roc_nix_tm_tree tree;
950 : : struct roc_nix_sq *s_sq;
951 : : bool once = false;
952 : : uint16_t qid, s_qid;
953 : : struct nix *nix;
954 : : int rc;
955 : :
956 : : nix = roc_nix_to_nix_priv(roc_nix);
957 : :
958 : : /* Need not do anything if tree is in disabled state */
959 [ # # ]: 0 : if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
960 : : return 0;
961 : :
962 : 0 : qid = sq->qid;
963 : 0 : tree = nix->tm_tree;
964 : : list = nix_tm_node_list(nix, tree);
965 : :
966 : : /* Find the node for this SQ */
967 : 0 : node = nix_tm_node_search(nix, qid, tree);
968 [ # # ]: 0 : if (!node) {
969 : 0 : plt_err("Invalid node for sq %u", qid);
970 : 0 : return -EFAULT;
971 : : }
972 : :
973 : : /* Enable all the siblings back */
974 [ # # ]: 0 : TAILQ_FOREACH(sibling, list, node) {
975 [ # # ]: 0 : if (sibling->parent != node->parent)
976 : 0 : continue;
977 : :
978 [ # # ]: 0 : if (sibling->id == qid)
979 : 0 : continue;
980 : :
981 [ # # ]: 0 : if (!(sibling->flags & NIX_TM_NODE_ENABLED))
982 : 0 : continue;
983 : :
984 : 0 : s_qid = sibling->id;
985 : 0 : s_sq = nix->sqs[s_qid];
986 [ # # ]: 0 : if (!s_sq)
987 : 0 : continue;
988 : :
989 [ # # ]: 0 : if (!once) {
990 : : /* Enable back if any SQ is still present */
991 : 0 : rc = nix_tm_smq_xoff(nix, node->parent, false);
992 [ # # ]: 0 : if (rc) {
993 : 0 : plt_err("Failed to enable smq %u, rc=%d",
994 : : node->parent->hw_id, rc);
995 : 0 : return rc;
996 : : }
997 : : once = true;
998 : : }
999 : :
1000 : 0 : rc = roc_nix_tm_sq_aura_fc(s_sq, true);
1001 [ # # ]: 0 : if (rc) {
1002 : 0 : plt_err("Failed to enable sqb aura fc, rc=%d", rc);
1003 : 0 : return rc;
1004 : : }
1005 : : }
1006 : :
1007 : : return 0;
1008 : : }
1009 : :
1010 : : int
1011 : 0 : nix_tm_sq_sched_conf(struct nix *nix, struct nix_tm_node *node,
1012 : : bool rr_quantum_only)
1013 : : {
1014 : 0 : struct mbox *mbox = mbox_get((&nix->dev)->mbox);
1015 : 0 : uint16_t qid = node->id, smq;
1016 : : uint64_t rr_quantum;
1017 : : int rc;
1018 : :
1019 : 0 : smq = node->parent->hw_id;
1020 [ # # ]: 0 : rr_quantum = nix_tm_weight_to_rr_quantum(node->weight);
1021 : :
1022 [ # # ]: 0 : if (rr_quantum_only)
1023 : 0 : plt_tm_dbg("Update sq(%u) rr_quantum 0x%" PRIx64, qid,
1024 : : rr_quantum);
1025 : : else
1026 : 0 : plt_tm_dbg("Enabling sq(%u)->smq(%u), rr_quantum 0x%" PRIx64,
1027 : : qid, smq, rr_quantum);
1028 : :
1029 [ # # ]: 0 : if (qid > nix->nb_tx_queues) {
1030 : : rc = -EFAULT;
1031 : 0 : goto exit;
1032 : : }
1033 : :
1034 [ # # ]: 0 : if (roc_model_is_cn9k()) {
1035 : : struct nix_aq_enq_req *aq;
1036 : :
1037 : 0 : aq = mbox_alloc_msg_nix_aq_enq(mbox);
1038 [ # # ]: 0 : if (!aq) {
1039 : : rc = -ENOSPC;
1040 : 0 : goto exit;
1041 : : }
1042 : :
1043 : 0 : aq->qidx = qid;
1044 : 0 : aq->ctype = NIX_AQ_CTYPE_SQ;
1045 : 0 : aq->op = NIX_AQ_INSTOP_WRITE;
1046 : :
1047 : : /* smq update only when needed */
1048 [ # # ]: 0 : if (!rr_quantum_only) {
1049 : 0 : aq->sq.smq = smq;
1050 : 0 : aq->sq_mask.smq = ~aq->sq_mask.smq;
1051 : : }
1052 : 0 : aq->sq.smq_rr_quantum = rr_quantum;
1053 : 0 : aq->sq_mask.smq_rr_quantum = ~aq->sq_mask.smq_rr_quantum;
1054 : : } else {
1055 : : struct nix_cn10k_aq_enq_req *aq;
1056 : :
1057 : 0 : aq = mbox_alloc_msg_nix_cn10k_aq_enq(mbox);
1058 [ # # ]: 0 : if (!aq) {
1059 : : rc = -ENOSPC;
1060 : 0 : goto exit;
1061 : : }
1062 : :
1063 : 0 : aq->qidx = qid;
1064 : 0 : aq->ctype = NIX_AQ_CTYPE_SQ;
1065 : 0 : aq->op = NIX_AQ_INSTOP_WRITE;
1066 : :
1067 : : /* smq update only when needed */
1068 [ # # ]: 0 : if (!rr_quantum_only) {
1069 : 0 : aq->sq.smq = smq;
1070 : 0 : aq->sq_mask.smq = ~aq->sq_mask.smq;
1071 : : }
1072 : 0 : aq->sq.smq_rr_weight = rr_quantum;
1073 : 0 : aq->sq_mask.smq_rr_weight = ~aq->sq_mask.smq_rr_weight;
1074 : : }
1075 : :
1076 : 0 : rc = mbox_process(mbox);
1077 [ # # ]: 0 : if (rc)
1078 : 0 : plt_err("Failed to set smq, rc=%d", rc);
1079 : 0 : exit:
1080 : : mbox_put(mbox);
1081 : 0 : return rc;
1082 : : }
1083 : :
1084 : : int
1085 : 0 : nix_tm_release_resources(struct nix *nix, uint8_t hw_lvl, bool contig,
1086 : : bool above_thresh)
1087 : : {
1088 : : uint16_t avail, thresh, to_free = 0, schq;
1089 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
1090 : : struct nix_txsch_free_req *req;
1091 : : struct plt_bitmap *bmp;
1092 : 0 : uint64_t slab = 0;
1093 : 0 : uint32_t pos = 0;
1094 : : int rc = -ENOSPC;
1095 : :
1096 [ # # ]: 0 : bmp = contig ? nix->schq_contig_bmp[hw_lvl] : nix->schq_bmp[hw_lvl];
1097 [ # # ]: 0 : thresh =
1098 : 0 : contig ? nix->contig_rsvd[hw_lvl] : nix->discontig_rsvd[hw_lvl];
1099 : : plt_bitmap_scan_init(bmp);
1100 : :
1101 : 0 : avail = nix_tm_resource_avail(nix, hw_lvl, contig);
1102 : :
1103 [ # # ]: 0 : if (above_thresh) {
1104 : : /* Release only above threshold */
1105 [ # # ]: 0 : if (avail > thresh)
1106 : 0 : to_free = avail - thresh;
1107 : : } else {
1108 : : /* Release everything */
1109 : : to_free = avail;
1110 : : }
1111 : :
1112 : : /* Now release resources to AF */
1113 [ # # ]: 0 : while (to_free) {
1114 [ # # # # ]: 0 : if (!slab && !plt_bitmap_scan(bmp, &pos, &slab))
1115 : : break;
1116 : :
1117 [ # # ]: 0 : schq = bitmap_ctzll(slab);
1118 : 0 : slab &= ~(1ULL << schq);
1119 : 0 : schq += pos;
1120 : :
1121 : : /* Free to AF */
1122 : 0 : req = mbox_alloc_msg_nix_txsch_free(mbox_get(mbox));
1123 [ # # ]: 0 : if (req == NULL) {
1124 : : mbox_put(mbox);
1125 : 0 : return rc;
1126 : : }
1127 : 0 : req->flags = 0;
1128 : 0 : req->schq_lvl = hw_lvl;
1129 : 0 : req->schq = schq;
1130 : 0 : rc = mbox_process(mbox);
1131 [ # # ]: 0 : if (rc) {
1132 [ # # # # : 0 : plt_err("failed to release hwres %s(%u) rc %d",
# # ]
1133 : : nix_tm_hwlvl2str(hw_lvl), schq, rc);
1134 : : mbox_put(mbox);
1135 : 0 : return rc;
1136 : : }
1137 : : mbox_put(mbox);
1138 [ # # # # : 0 : plt_tm_dbg("Released hwres %s(%u)", nix_tm_hwlvl2str(hw_lvl),
# # ]
1139 : : schq);
1140 : 0 : plt_bitmap_clear(bmp, schq);
1141 : 0 : to_free--;
1142 : : }
1143 : :
1144 [ # # ]: 0 : if (to_free) {
1145 : 0 : plt_err("resource inconsistency for %s(%u)",
1146 : : nix_tm_hwlvl2str(hw_lvl), contig);
1147 : 0 : return -EFAULT;
1148 : : }
1149 : : return 0;
1150 : : }
1151 : :
1152 : : int
1153 : 0 : nix_tm_free_node_resource(struct nix *nix, struct nix_tm_node *node)
1154 : : {
1155 : 0 : struct mbox *mbox = mbox_get((&nix->dev)->mbox);
1156 : : struct nix_txsch_free_req *req;
1157 : : struct plt_bitmap *bmp;
1158 : : uint16_t avail, hw_id;
1159 : : uint8_t hw_lvl;
1160 : : int rc = -ENOSPC;
1161 : :
1162 : 0 : hw_lvl = node->hw_lvl;
1163 : 0 : hw_id = node->hw_id;
1164 : 0 : bmp = nix->schq_bmp[hw_lvl];
1165 : : /* Free specific HW resource */
1166 [ # # # # : 0 : plt_tm_dbg("Free hwres %s(%u) lvl %u id %u (%p)",
# # ]
1167 : : nix_tm_hwlvl2str(node->hw_lvl), hw_id, node->lvl, node->id,
1168 : : node);
1169 : :
1170 : 0 : avail = nix_tm_resource_avail(nix, hw_lvl, false);
1171 : : /* Always for now free to discontiguous queue when avail
1172 : : * is not sufficient.
1173 : : */
1174 [ # # # # ]: 0 : if (nix->discontig_rsvd[hw_lvl] &&
1175 : : avail < nix->discontig_rsvd[hw_lvl]) {
1176 : : PLT_ASSERT(hw_id < NIX_TM_MAX_HW_TXSCHQ);
1177 : : PLT_ASSERT(plt_bitmap_get(bmp, hw_id) == 0);
1178 : 0 : plt_bitmap_set(bmp, hw_id);
1179 : 0 : node->hw_id = NIX_TM_HW_ID_INVALID;
1180 : 0 : node->flags &= ~NIX_TM_NODE_HWRES;
1181 : : rc = 0;
1182 : 0 : goto exit;
1183 : : }
1184 : :
1185 : : /* Free to AF */
1186 : 0 : req = mbox_alloc_msg_nix_txsch_free(mbox);
1187 [ # # ]: 0 : if (req == NULL)
1188 : 0 : goto exit;
1189 : 0 : req->flags = 0;
1190 : 0 : req->schq_lvl = node->hw_lvl;
1191 : 0 : req->schq = hw_id;
1192 : 0 : rc = mbox_process(mbox);
1193 [ # # ]: 0 : if (rc) {
1194 [ # # # # : 0 : plt_err("failed to release hwres %s(%u) rc %d",
# # ]
1195 : : nix_tm_hwlvl2str(node->hw_lvl), hw_id, rc);
1196 : 0 : goto exit;
1197 : : }
1198 : :
1199 : : /* Mark parent as dirty for reallocing it's children */
1200 [ # # ]: 0 : if (node->parent)
1201 : 0 : node->parent->child_realloc = true;
1202 : :
1203 : 0 : node->hw_id = NIX_TM_HW_ID_INVALID;
1204 : 0 : node->flags &= ~NIX_TM_NODE_HWRES;
1205 [ # # # # : 0 : plt_tm_dbg("Released hwres %s(%u) to af",
# # ]
1206 : : nix_tm_hwlvl2str(node->hw_lvl), hw_id);
1207 : : rc = 0;
1208 : 0 : exit:
1209 : : mbox_put(mbox);
1210 : 0 : return rc;
1211 : : }
1212 : :
1213 : : int
1214 : 0 : nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id,
1215 : : enum roc_nix_tm_tree tree, bool free)
1216 : : {
1217 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1218 : : struct nix_tm_shaper_profile *profile;
1219 : : struct nix_tm_node *node, *child;
1220 : : struct nix_tm_node_list *list;
1221 : : uint32_t profile_id;
1222 : : int rc;
1223 : :
1224 : 0 : plt_tm_dbg("Delete node id %u tree %u", node_id, tree);
1225 : :
1226 : 0 : node = nix_tm_node_search(nix, node_id, tree);
1227 [ # # ]: 0 : if (!node)
1228 : : return NIX_ERR_TM_INVALID_NODE;
1229 : :
1230 : : list = nix_tm_node_list(nix, tree);
1231 : : /* Check for any existing children */
1232 [ # # ]: 0 : TAILQ_FOREACH(child, list, node) {
1233 [ # # ]: 0 : if (child->parent == node)
1234 : : return NIX_ERR_TM_CHILD_EXISTS;
1235 : : }
1236 : :
1237 : : /* Remove shaper profile reference */
1238 : 0 : profile_id = node->shaper_profile_id;
1239 : 0 : profile = nix_tm_shaper_profile_search(nix, profile_id);
1240 : :
1241 : : /* Free hw resource locally */
1242 [ # # ]: 0 : if (node->flags & NIX_TM_NODE_HWRES) {
1243 : 0 : rc = nix_tm_free_node_resource(nix, node);
1244 [ # # ]: 0 : if (rc)
1245 : : return rc;
1246 : : }
1247 : :
1248 [ # # ]: 0 : if (profile)
1249 : 0 : profile->ref_cnt--;
1250 : :
1251 [ # # ]: 0 : TAILQ_REMOVE(list, node, node);
1252 : :
1253 [ # # # # : 0 : plt_tm_dbg("Deleted node %s lvl %u id %u, prio 0x%x weight 0x%x "
# # # # ]
1254 : : "parent %u profile 0x%x tree %u (%p)",
1255 : : nix_tm_hwlvl2str(node->hw_lvl), node->lvl, node->id,
1256 : : node->priority, node->weight,
1257 : : node->parent ? node->parent->id : UINT32_MAX,
1258 : : node->shaper_profile_id, tree, node);
1259 : : /* Free only if requested */
1260 [ # # ]: 0 : if (free)
1261 : 0 : nix_tm_node_free(node);
1262 : : return 0;
1263 : : }
1264 : :
1265 : : static int
1266 : 0 : nix_tm_assign_hw_id(struct nix *nix, struct nix_tm_node *parent,
1267 : : uint16_t *contig_id, int *contig_cnt,
1268 : : struct nix_tm_node_list *list)
1269 : : {
1270 : : struct nix_tm_node *child;
1271 : : struct plt_bitmap *bmp;
1272 : : uint8_t child_hw_lvl;
1273 : : int spare_schq = -1;
1274 : 0 : uint32_t pos = 0;
1275 : : uint64_t slab;
1276 : : uint16_t schq;
1277 : :
1278 : 0 : child_hw_lvl = parent->hw_lvl - 1;
1279 [ # # ]: 0 : bmp = nix->schq_bmp[child_hw_lvl];
1280 : : plt_bitmap_scan_init(bmp);
1281 : 0 : slab = 0;
1282 : :
1283 : : /* Save spare schq if it is case of RR + SP */
1284 [ # # # # ]: 0 : if (parent->rr_prio != 0xf && *contig_cnt > 1)
1285 : 0 : spare_schq = *contig_id + parent->rr_prio;
1286 : :
1287 [ # # ]: 0 : TAILQ_FOREACH(child, list, node) {
1288 [ # # ]: 0 : if (!child->parent)
1289 : 0 : continue;
1290 [ # # ]: 0 : if (child->parent->id != parent->id)
1291 : 0 : continue;
1292 : :
1293 : : /* Resource never expected to be present */
1294 [ # # ]: 0 : if (child->flags & NIX_TM_NODE_HWRES) {
1295 [ # # # # : 0 : plt_err("Resource exists for child (%s)%u, id %u (%p)",
# # ]
1296 : : nix_tm_hwlvl2str(child->hw_lvl), child->hw_id,
1297 : : child->id, child);
1298 : 0 : return -EFAULT;
1299 : : }
1300 : :
1301 [ # # ]: 0 : if (!slab)
1302 : 0 : plt_bitmap_scan(bmp, &pos, &slab);
1303 : :
1304 [ # # # # ]: 0 : if (child->priority == parent->rr_prio && spare_schq != -1) {
1305 : : /* Use spare schq first if present */
1306 : 0 : schq = spare_schq;
1307 : : spare_schq = -1;
1308 : 0 : *contig_cnt = *contig_cnt - 1;
1309 : :
1310 [ # # ]: 0 : } else if (child->priority == parent->rr_prio) {
1311 : : /* Assign a discontiguous queue */
1312 [ # # ]: 0 : if (!slab) {
1313 : 0 : plt_err("Schq not found for Child %u "
1314 : : "lvl %u (%p)",
1315 : : child->id, child->lvl, child);
1316 : 0 : return -ENOENT;
1317 : : }
1318 : :
1319 : 0 : schq = bitmap_ctzll(slab);
1320 : 0 : slab &= ~(1ULL << schq);
1321 : 0 : schq += pos;
1322 : 0 : plt_bitmap_clear(bmp, schq);
1323 : : } else {
1324 : : /* Assign a contiguous queue */
1325 : 0 : schq = *contig_id + child->priority;
1326 : 0 : *contig_cnt = *contig_cnt - 1;
1327 : : }
1328 : :
1329 [ # # # # : 0 : plt_tm_dbg("Resource %s(%u), for lvl %u id %u(%p)",
# # ]
1330 : : nix_tm_hwlvl2str(child->hw_lvl), schq, child->lvl,
1331 : : child->id, child);
1332 : :
1333 : 0 : child->hw_id = schq;
1334 : 0 : child->parent_hw_id = parent->hw_id;
1335 : 0 : child->flags |= NIX_TM_NODE_HWRES;
1336 : : }
1337 : :
1338 : : return 0;
1339 : : }
1340 : :
1341 : : int
1342 : 0 : nix_tm_assign_resources(struct nix *nix, enum roc_nix_tm_tree tree)
1343 : : {
1344 : : struct nix_tm_node *parent, *root = NULL;
1345 : : struct plt_bitmap *bmp, *bmp_contig;
1346 : : struct nix_tm_node_list *list;
1347 : : uint8_t child_hw_lvl, hw_lvl;
1348 : : uint16_t contig_id, j;
1349 : 0 : uint64_t slab = 0;
1350 : 0 : uint32_t pos = 0;
1351 : : int cnt, rc;
1352 : :
1353 : : list = nix_tm_node_list(nix, tree);
1354 : : /* Walk from TL1 to TL4 parents */
1355 [ # # ]: 0 : for (hw_lvl = NIX_TXSCH_LVL_TL1; hw_lvl > 0; hw_lvl--) {
1356 [ # # ]: 0 : TAILQ_FOREACH(parent, list, node) {
1357 : 0 : child_hw_lvl = parent->hw_lvl - 1;
1358 [ # # ]: 0 : if (parent->hw_lvl != hw_lvl)
1359 : 0 : continue;
1360 : :
1361 : : /* Remember root for future */
1362 [ # # ]: 0 : if (parent->hw_lvl == nix->tm_root_lvl)
1363 : : root = parent;
1364 : :
1365 [ # # ]: 0 : if (!parent->child_realloc) {
1366 : : /* Skip when parent is not dirty */
1367 [ # # ]: 0 : if (nix_tm_child_res_valid(list, parent))
1368 : 0 : continue;
1369 : 0 : plt_err("Parent not dirty but invalid "
1370 : : "child res parent id %u(lvl %u)",
1371 : : parent->id, parent->lvl);
1372 : 0 : return -EFAULT;
1373 : : }
1374 : :
1375 : 0 : bmp_contig = nix->schq_contig_bmp[child_hw_lvl];
1376 : :
1377 : : /* Prealloc contiguous indices for a parent */
1378 : 0 : contig_id = NIX_TM_MAX_HW_TXSCHQ;
1379 : 0 : cnt = (int)parent->max_prio + 1;
1380 [ # # ]: 0 : if (cnt > 0) {
1381 : : plt_bitmap_scan_init(bmp_contig);
1382 [ # # ]: 0 : if (!plt_bitmap_scan(bmp_contig, &pos, &slab)) {
1383 : 0 : plt_err("Contig schq not found");
1384 : 0 : return -ENOENT;
1385 : : }
1386 [ # # ]: 0 : contig_id = pos + bitmap_ctzll(slab);
1387 : :
1388 : : /* Check if we have enough */
1389 [ # # ]: 0 : for (j = contig_id; j < contig_id + cnt; j++) {
1390 [ # # ]: 0 : if (!plt_bitmap_get(bmp_contig, j))
1391 : : break;
1392 : : }
1393 : :
1394 [ # # ]: 0 : if (j != contig_id + cnt) {
1395 : 0 : plt_err("Contig schq not sufficient");
1396 : 0 : return -ENOENT;
1397 : : }
1398 : :
1399 [ # # ]: 0 : for (j = contig_id; j < contig_id + cnt; j++)
1400 : 0 : plt_bitmap_clear(bmp_contig, j);
1401 : : }
1402 : :
1403 : : /* Assign hw id to all children */
1404 : 0 : rc = nix_tm_assign_hw_id(nix, parent, &contig_id, &cnt,
1405 : : list);
1406 [ # # ]: 0 : if (cnt || rc) {
1407 : 0 : plt_err("Unexpected err, contig res alloc, "
1408 : : "parent %u, of %s, rc=%d, cnt=%d",
1409 : : parent->id, nix_tm_hwlvl2str(hw_lvl),
1410 : : rc, cnt);
1411 : 0 : return -EFAULT;
1412 : : }
1413 : :
1414 : : /* Clear the dirty bit as children's
1415 : : * resources are reallocated.
1416 : : */
1417 : 0 : parent->child_realloc = false;
1418 : : }
1419 : : }
1420 : :
1421 : : /* Root is always expected to be there */
1422 [ # # ]: 0 : if (!root)
1423 : : return -EFAULT;
1424 : :
1425 [ # # ]: 0 : if (root->flags & NIX_TM_NODE_HWRES)
1426 : : return 0;
1427 : :
1428 : : /* Process root node */
1429 : 0 : bmp = nix->schq_bmp[nix->tm_root_lvl];
1430 : : plt_bitmap_scan_init(bmp);
1431 [ # # ]: 0 : if (!plt_bitmap_scan(bmp, &pos, &slab)) {
1432 : 0 : plt_err("Resource not allocated for root");
1433 : 0 : return -EIO;
1434 : : }
1435 : :
1436 [ # # ]: 0 : root->hw_id = pos + bitmap_ctzll(slab);
1437 : 0 : root->flags |= NIX_TM_NODE_HWRES;
1438 : 0 : plt_bitmap_clear(bmp, root->hw_id);
1439 : :
1440 : : /* Get TL1 id as well when root is not TL1 */
1441 [ # # ]: 0 : if (!nix_tm_have_tl1_access(nix)) {
1442 : 0 : bmp = nix->schq_bmp[NIX_TXSCH_LVL_TL1];
1443 : :
1444 : : plt_bitmap_scan_init(bmp);
1445 [ # # ]: 0 : if (!plt_bitmap_scan(bmp, &pos, &slab)) {
1446 : 0 : plt_err("Resource not found for TL1");
1447 : 0 : return -EIO;
1448 : : }
1449 [ # # ]: 0 : root->parent_hw_id = pos + bitmap_ctzll(slab);
1450 : 0 : plt_bitmap_clear(bmp, root->parent_hw_id);
1451 : : }
1452 : :
1453 [ # # # # : 0 : plt_tm_dbg("Resource %s(%u) for root(id %u) (%p)",
# # ]
1454 : : nix_tm_hwlvl2str(root->hw_lvl), root->hw_id, root->id, root);
1455 : :
1456 : 0 : return 0;
1457 : : }
1458 : :
1459 : : void
1460 : 0 : nix_tm_copy_rsp_to_nix(struct nix *nix, struct nix_txsch_alloc_rsp *rsp)
1461 : : {
1462 : : uint8_t lvl;
1463 : : uint16_t i;
1464 : :
1465 [ # # ]: 0 : for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
1466 [ # # ]: 0 : for (i = 0; i < rsp->schq[lvl]; i++)
1467 : 0 : plt_bitmap_set(nix->schq_bmp[lvl],
1468 : 0 : rsp->schq_list[lvl][i]);
1469 : :
1470 [ # # ]: 0 : for (i = 0; i < rsp->schq_contig[lvl]; i++)
1471 : 0 : plt_bitmap_set(nix->schq_contig_bmp[lvl],
1472 : 0 : rsp->schq_contig_list[lvl][i]);
1473 : : }
1474 : 0 : }
1475 : :
1476 : : int
1477 : 0 : nix_tm_alloc_txschq(struct nix *nix, enum roc_nix_tm_tree tree)
1478 : : {
1479 : : uint16_t schq_contig[NIX_TXSCH_LVL_CNT];
1480 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
1481 : : uint16_t schq[NIX_TXSCH_LVL_CNT];
1482 : : struct nix_txsch_alloc_req *req;
1483 : : struct nix_txsch_alloc_rsp *rsp;
1484 : : uint8_t hw_lvl, i;
1485 : : bool pend;
1486 : : int rc;
1487 : :
1488 : : memset(schq, 0, sizeof(schq));
1489 : : memset(schq_contig, 0, sizeof(schq_contig));
1490 : :
1491 : : /* Estimate requirement */
1492 : 0 : rc = nix_tm_resource_estimate(nix, schq_contig, schq, tree);
1493 [ # # ]: 0 : if (!rc)
1494 : : return 0;
1495 : :
1496 : : /* Release existing contiguous resources when realloc requested
1497 : : * as there is no way to guarantee continuity of old with new.
1498 : : */
1499 [ # # ]: 0 : for (hw_lvl = 0; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
1500 [ # # ]: 0 : if (schq_contig[hw_lvl])
1501 : 0 : nix_tm_release_resources(nix, hw_lvl, true, false);
1502 : : }
1503 : :
1504 : : /* Alloc as needed */
1505 : : do {
1506 : : pend = false;
1507 : 0 : req = mbox_alloc_msg_nix_txsch_alloc(mbox_get(mbox));
1508 [ # # ]: 0 : if (!req) {
1509 : : mbox_put(mbox);
1510 : : rc = -ENOMEM;
1511 : 0 : goto alloc_err;
1512 : : }
1513 : 0 : mbox_memcpy(req->schq, schq, sizeof(req->schq));
1514 : 0 : mbox_memcpy(req->schq_contig, schq_contig,
1515 : : sizeof(req->schq_contig));
1516 : :
1517 : : /* Each alloc can be at max of MAX_TXSCHQ_PER_FUNC per level.
1518 : : * So split alloc to multiple requests.
1519 : : */
1520 [ # # ]: 0 : for (i = 0; i < NIX_TXSCH_LVL_CNT; i++) {
1521 [ # # ]: 0 : if (req->schq[i] > MAX_TXSCHQ_PER_FUNC)
1522 : 0 : req->schq[i] = MAX_TXSCHQ_PER_FUNC;
1523 : 0 : schq[i] -= req->schq[i];
1524 : :
1525 [ # # ]: 0 : if (req->schq_contig[i] > MAX_TXSCHQ_PER_FUNC)
1526 : 0 : req->schq_contig[i] = MAX_TXSCHQ_PER_FUNC;
1527 : 0 : schq_contig[i] -= req->schq_contig[i];
1528 : :
1529 [ # # # # ]: 0 : if (schq[i] || schq_contig[i])
1530 : : pend = true;
1531 : : }
1532 : :
1533 : : rc = mbox_process_msg(mbox, (void *)&rsp);
1534 [ # # ]: 0 : if (rc) {
1535 : : mbox_put(mbox);
1536 : 0 : goto alloc_err;
1537 : : }
1538 : :
1539 : 0 : nix_tm_copy_rsp_to_nix(nix, rsp);
1540 : : mbox_put(mbox);
1541 [ # # ]: 0 : } while (pend);
1542 : :
1543 : 0 : nix->tm_link_cfg_lvl = rsp->link_cfg_lvl;
1544 : 0 : nix->tm_aggr_lvl_rr_prio = rsp->aggr_lvl_rr_prio;
1545 : 0 : return 0;
1546 : 0 : alloc_err:
1547 [ # # ]: 0 : for (i = 0; i < NIX_TXSCH_LVL_CNT; i++) {
1548 [ # # ]: 0 : if (nix_tm_release_resources(nix, i, true, false))
1549 : 0 : plt_err("Failed to release contig resources of "
1550 : : "lvl %d on error",
1551 : : i);
1552 [ # # ]: 0 : if (nix_tm_release_resources(nix, i, false, false))
1553 : 0 : plt_err("Failed to release discontig resources of "
1554 : : "lvl %d on error",
1555 : : i);
1556 : : }
1557 : : return rc;
1558 : : }
1559 : :
1560 : : int
1561 : 0 : nix_tm_prepare_default_tree(struct roc_nix *roc_nix)
1562 : : {
1563 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1564 [ # # ]: 0 : uint32_t nonleaf_id = nix->nb_tx_queues;
1565 : : struct nix_tm_node *node = NULL;
1566 : : uint8_t leaf_lvl, lvl, lvl_end;
1567 : : uint32_t parent, i;
1568 : : int rc = 0;
1569 : :
1570 : : /* Add ROOT, SCH1, SCH2, SCH3, [SCH4] nodes */
1571 : : parent = ROC_NIX_TM_NODE_ID_INVALID;
1572 : : /* With TL1 access we have an extra level */
1573 [ # # ]: 0 : lvl_end = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH4 :
1574 : : ROC_TM_LVL_SCH3);
1575 : :
1576 [ # # ]: 0 : for (lvl = ROC_TM_LVL_ROOT; lvl <= lvl_end; lvl++) {
1577 : : rc = -ENOMEM;
1578 : 0 : node = nix_tm_node_alloc();
1579 [ # # ]: 0 : if (!node)
1580 : 0 : goto error;
1581 : :
1582 : 0 : node->id = nonleaf_id;
1583 : 0 : node->parent_id = parent;
1584 : 0 : node->priority = 0;
1585 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1586 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1587 : 0 : node->lvl = lvl;
1588 : 0 : node->tree = ROC_NIX_TM_DEFAULT;
1589 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1590 : :
1591 : 0 : rc = nix_tm_node_add(roc_nix, node);
1592 [ # # ]: 0 : if (rc)
1593 : 0 : goto error;
1594 : : parent = nonleaf_id;
1595 : 0 : nonleaf_id++;
1596 : : }
1597 : :
1598 [ # # ]: 0 : parent = nonleaf_id - 1;
1599 [ # # ]: 0 : leaf_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_QUEUE :
1600 : : ROC_TM_LVL_SCH4);
1601 : :
1602 : : /* Add leaf nodes */
1603 [ # # ]: 0 : for (i = 0; i < nix->nb_tx_queues; i++) {
1604 : : rc = -ENOMEM;
1605 : 0 : node = nix_tm_node_alloc();
1606 [ # # ]: 0 : if (!node)
1607 : 0 : goto error;
1608 : :
1609 : 0 : node->id = i;
1610 : 0 : node->parent_id = parent;
1611 : 0 : node->priority = 0;
1612 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1613 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1614 : 0 : node->lvl = leaf_lvl;
1615 : 0 : node->tree = ROC_NIX_TM_DEFAULT;
1616 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1617 : :
1618 : 0 : rc = nix_tm_node_add(roc_nix, node);
1619 [ # # ]: 0 : if (rc)
1620 : 0 : goto error;
1621 : : }
1622 : :
1623 : : return 0;
1624 : 0 : error:
1625 : 0 : nix_tm_node_free(node);
1626 : 0 : return rc;
1627 : : }
1628 : :
1629 : : int
1630 : 0 : roc_nix_tm_prepare_rate_limited_tree(struct roc_nix *roc_nix)
1631 : : {
1632 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1633 [ # # ]: 0 : uint32_t nonleaf_id = nix->nb_tx_queues;
1634 : : struct nix_tm_node *node = NULL;
1635 : : uint8_t leaf_lvl, lvl, lvl_end;
1636 : : uint32_t parent, i;
1637 : : int rc = 0;
1638 : :
1639 : : /* Add ROOT, SCH1, SCH2 nodes */
1640 : : parent = ROC_NIX_TM_NODE_ID_INVALID;
1641 [ # # ]: 0 : lvl_end = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH3 :
1642 : : ROC_TM_LVL_SCH2);
1643 : :
1644 [ # # ]: 0 : for (lvl = ROC_TM_LVL_ROOT; lvl <= lvl_end; lvl++) {
1645 : : rc = -ENOMEM;
1646 : 0 : node = nix_tm_node_alloc();
1647 [ # # ]: 0 : if (!node)
1648 : 0 : goto error;
1649 : :
1650 : 0 : node->id = nonleaf_id;
1651 : 0 : node->parent_id = parent;
1652 : 0 : node->priority = 0;
1653 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1654 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1655 : 0 : node->lvl = lvl;
1656 : 0 : node->tree = ROC_NIX_TM_RLIMIT;
1657 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1658 : :
1659 : 0 : rc = nix_tm_node_add(roc_nix, node);
1660 [ # # ]: 0 : if (rc)
1661 : 0 : goto error;
1662 : : parent = nonleaf_id;
1663 : 0 : nonleaf_id++;
1664 : : }
1665 : :
1666 : : /* SMQ is mapped to SCH4 when we have TL1 access and SCH3 otherwise */
1667 [ # # ]: 0 : lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH4 : ROC_TM_LVL_SCH3);
1668 : :
1669 : : /* Add per queue SMQ nodes i.e SCH4 / SCH3 */
1670 [ # # ]: 0 : for (i = 0; i < nix->nb_tx_queues; i++) {
1671 : : rc = -ENOMEM;
1672 : 0 : node = nix_tm_node_alloc();
1673 [ # # ]: 0 : if (!node)
1674 : 0 : goto error;
1675 : :
1676 : 0 : node->id = nonleaf_id + i;
1677 : 0 : node->parent_id = parent;
1678 : 0 : node->priority = 0;
1679 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1680 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1681 : 0 : node->lvl = lvl;
1682 : 0 : node->tree = ROC_NIX_TM_RLIMIT;
1683 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1684 : :
1685 : 0 : rc = nix_tm_node_add(roc_nix, node);
1686 [ # # ]: 0 : if (rc)
1687 : 0 : goto error;
1688 : : }
1689 : :
1690 : : parent = nonleaf_id;
1691 [ # # ]: 0 : leaf_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_QUEUE :
1692 : : ROC_TM_LVL_SCH4);
1693 : :
1694 : : /* Add leaf nodes */
1695 [ # # ]: 0 : for (i = 0; i < nix->nb_tx_queues; i++) {
1696 : : rc = -ENOMEM;
1697 : 0 : node = nix_tm_node_alloc();
1698 [ # # ]: 0 : if (!node)
1699 : 0 : goto error;
1700 : :
1701 : 0 : node->id = i;
1702 : 0 : node->parent_id = parent + i;
1703 : 0 : node->priority = 0;
1704 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1705 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1706 : 0 : node->lvl = leaf_lvl;
1707 : 0 : node->tree = ROC_NIX_TM_RLIMIT;
1708 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1709 : :
1710 : 0 : rc = nix_tm_node_add(roc_nix, node);
1711 [ # # ]: 0 : if (rc)
1712 : 0 : goto error;
1713 : : }
1714 : :
1715 : : return 0;
1716 : 0 : error:
1717 : 0 : nix_tm_node_free(node);
1718 : 0 : return rc;
1719 : : }
1720 : :
1721 : : int
1722 : 0 : roc_nix_tm_pfc_prepare_tree(struct roc_nix *roc_nix)
1723 : : {
1724 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1725 : : uint8_t leaf_lvl, lvl, lvl_start, lvl_end;
1726 [ # # ]: 0 : uint32_t nonleaf_id = nix->nb_tx_queues;
1727 : : struct nix_tm_node *node = NULL;
1728 : : uint32_t tl2_node_id;
1729 : : uint32_t parent, i;
1730 : : int rc = -ENOMEM;
1731 : :
1732 : : parent = ROC_NIX_TM_NODE_ID_INVALID;
1733 [ # # ]: 0 : lvl_end = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH3 :
1734 : : ROC_TM_LVL_SCH2);
1735 [ # # ]: 0 : leaf_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_QUEUE :
1736 : : ROC_TM_LVL_SCH4);
1737 : :
1738 : : /* TL1 node */
1739 : 0 : node = nix_tm_node_alloc();
1740 [ # # ]: 0 : if (!node)
1741 : 0 : goto error;
1742 : :
1743 : 0 : node->id = nonleaf_id;
1744 : 0 : node->parent_id = parent;
1745 : 0 : node->priority = 0;
1746 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1747 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1748 : 0 : node->lvl = ROC_TM_LVL_ROOT;
1749 : 0 : node->tree = ROC_NIX_TM_PFC;
1750 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1751 : :
1752 : 0 : rc = nix_tm_node_add(roc_nix, node);
1753 [ # # ]: 0 : if (rc)
1754 : 0 : goto error;
1755 : :
1756 : : parent = nonleaf_id;
1757 : 0 : nonleaf_id++;
1758 : :
1759 : : lvl_start = ROC_TM_LVL_SCH1;
1760 [ # # ]: 0 : if (roc_nix_is_pf(roc_nix)) {
1761 : : /* TL2 node */
1762 : : rc = -ENOMEM;
1763 : 0 : node = nix_tm_node_alloc();
1764 [ # # ]: 0 : if (!node)
1765 : 0 : goto error;
1766 : :
1767 : 0 : node->id = nonleaf_id;
1768 : 0 : node->parent_id = parent;
1769 : 0 : node->priority = 0;
1770 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1771 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1772 : 0 : node->lvl = ROC_TM_LVL_SCH1;
1773 : 0 : node->tree = ROC_NIX_TM_PFC;
1774 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1775 : :
1776 : 0 : rc = nix_tm_node_add(roc_nix, node);
1777 [ # # ]: 0 : if (rc)
1778 : 0 : goto error;
1779 : :
1780 : : lvl_start = ROC_TM_LVL_SCH2;
1781 : : tl2_node_id = nonleaf_id;
1782 : 0 : nonleaf_id++;
1783 : : } else {
1784 : : tl2_node_id = parent;
1785 : : }
1786 : :
1787 [ # # ]: 0 : for (i = 0; i < nix->nb_tx_queues; i++) {
1788 : : parent = tl2_node_id;
1789 [ # # ]: 0 : for (lvl = lvl_start; lvl <= lvl_end; lvl++) {
1790 : : rc = -ENOMEM;
1791 : 0 : node = nix_tm_node_alloc();
1792 [ # # ]: 0 : if (!node)
1793 : 0 : goto error;
1794 : :
1795 : 0 : node->id = nonleaf_id;
1796 : 0 : node->parent_id = parent;
1797 : 0 : node->priority = 0;
1798 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1799 : 0 : node->shaper_profile_id =
1800 : : ROC_NIX_TM_SHAPER_PROFILE_NONE;
1801 : 0 : node->lvl = lvl;
1802 : 0 : node->tree = ROC_NIX_TM_PFC;
1803 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1804 : :
1805 : 0 : rc = nix_tm_node_add(roc_nix, node);
1806 [ # # ]: 0 : if (rc)
1807 : 0 : goto error;
1808 : :
1809 : : parent = nonleaf_id;
1810 : 0 : nonleaf_id++;
1811 : : }
1812 : :
1813 [ # # ]: 0 : lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH4 :
1814 : : ROC_TM_LVL_SCH3);
1815 : :
1816 : : rc = -ENOMEM;
1817 : 0 : node = nix_tm_node_alloc();
1818 [ # # ]: 0 : if (!node)
1819 : 0 : goto error;
1820 : :
1821 : 0 : node->id = nonleaf_id;
1822 : 0 : node->parent_id = parent;
1823 : 0 : node->priority = 0;
1824 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1825 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1826 : 0 : node->lvl = lvl;
1827 : 0 : node->tree = ROC_NIX_TM_PFC;
1828 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1829 : :
1830 : 0 : rc = nix_tm_node_add(roc_nix, node);
1831 [ # # ]: 0 : if (rc)
1832 : 0 : goto error;
1833 : :
1834 : : parent = nonleaf_id;
1835 : 0 : nonleaf_id++;
1836 : :
1837 : : rc = -ENOMEM;
1838 : 0 : node = nix_tm_node_alloc();
1839 [ # # ]: 0 : if (!node)
1840 : 0 : goto error;
1841 : :
1842 : 0 : node->id = i;
1843 : 0 : node->parent_id = parent;
1844 : 0 : node->priority = 0;
1845 : 0 : node->weight = NIX_TM_DFLT_RR_WT;
1846 : 0 : node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
1847 : 0 : node->lvl = leaf_lvl;
1848 : 0 : node->tree = ROC_NIX_TM_PFC;
1849 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
1850 : :
1851 : 0 : rc = nix_tm_node_add(roc_nix, node);
1852 [ # # ]: 0 : if (rc)
1853 : 0 : goto error;
1854 : : }
1855 : :
1856 : : return 0;
1857 : 0 : error:
1858 : 0 : nix_tm_node_free(node);
1859 : 0 : return rc;
1860 : : }
1861 : :
1862 : : int
1863 : 0 : nix_tm_free_resources(struct roc_nix *roc_nix, uint32_t tree_mask, bool hw_only)
1864 : : {
1865 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1866 : : struct nix_tm_shaper_profile *profile;
1867 : : struct nix_tm_node *node, *next_node;
1868 : : struct nix_tm_node_list *list;
1869 : : enum roc_nix_tm_tree tree;
1870 : : uint32_t profile_id;
1871 : : int rc = 0;
1872 : : int hw_lvl;
1873 : :
1874 [ # # ]: 0 : for (tree = 0; tree < ROC_NIX_TM_TREE_MAX; tree++) {
1875 [ # # ]: 0 : if (!(tree_mask & BIT(tree)))
1876 : 0 : continue;
1877 : :
1878 : 0 : plt_tm_dbg("Freeing resources of tree %u", tree);
1879 : :
1880 : : list = nix_tm_node_list(nix, tree);
1881 : : /* Flush and free resources from leaf */
1882 [ # # ]: 0 : for (hw_lvl = NIX_TXSCH_LVL_SMQ; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
1883 : 0 : next_node = TAILQ_FIRST(list);
1884 [ # # ]: 0 : while (next_node) {
1885 : : node = next_node;
1886 : 0 : next_node = TAILQ_NEXT(node, node);
1887 [ # # ]: 0 : if (node->hw_lvl != hw_lvl)
1888 : 0 : continue;
1889 : :
1890 [ # # # # ]: 0 : if (!nix_tm_is_leaf(nix, node->lvl) &&
1891 [ # # ]: 0 : node->flags & NIX_TM_NODE_HWRES) {
1892 : : /* Clear xoff in path for flush to succeed */
1893 : 0 : rc = nix_tm_clear_path_xoff(nix, node);
1894 [ # # ]: 0 : if (rc)
1895 : 0 : return rc;
1896 : 0 : rc = nix_tm_free_node_resource(nix, node);
1897 [ # # ]: 0 : if (rc)
1898 : 0 : return rc;
1899 : : }
1900 : : }
1901 : : }
1902 : :
1903 : : /* Leave software elements if needed */
1904 [ # # ]: 0 : if (hw_only)
1905 : 0 : continue;
1906 : :
1907 : 0 : next_node = TAILQ_FIRST(list);
1908 [ # # ]: 0 : while (next_node) {
1909 : : node = next_node;
1910 : 0 : next_node = TAILQ_NEXT(node, node);
1911 : :
1912 : 0 : plt_tm_dbg("Free node lvl %u id %u (%p)", node->lvl,
1913 : : node->id, node);
1914 : :
1915 : 0 : profile_id = node->shaper_profile_id;
1916 : 0 : profile = nix_tm_shaper_profile_search(nix, profile_id);
1917 [ # # ]: 0 : if (profile)
1918 : 0 : profile->ref_cnt--;
1919 : :
1920 [ # # ]: 0 : TAILQ_REMOVE(list, node, node);
1921 : 0 : nix_tm_node_free(node);
1922 : : }
1923 : : }
1924 : : return rc;
1925 : : }
1926 : :
1927 : : int
1928 : 0 : nix_tm_conf_init(struct roc_nix *roc_nix)
1929 : : {
1930 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1931 : : uint32_t bmp_sz, hw_lvl;
1932 : : void *bmp_mem;
1933 : : int rc, i;
1934 : :
1935 : : PLT_STATIC_ASSERT(sizeof(struct nix_tm_node) <= ROC_NIX_TM_NODE_SZ);
1936 : : PLT_STATIC_ASSERT(sizeof(struct nix_tm_shaper_profile) <=
1937 : : ROC_NIX_TM_SHAPER_PROFILE_SZ);
1938 : :
1939 : 0 : nix->tm_flags = 0;
1940 [ # # ]: 0 : for (i = 0; i < ROC_NIX_TM_TREE_MAX; i++)
1941 : 0 : TAILQ_INIT(&nix->trees[i]);
1942 : :
1943 : 0 : TAILQ_INIT(&nix->shaper_profile_list);
1944 : 0 : nix->tm_rate_min = 1E9; /* 1Gbps */
1945 : :
1946 : : rc = -ENOMEM;
1947 : : bmp_sz = plt_bitmap_get_memory_footprint(NIX_TM_MAX_HW_TXSCHQ);
1948 : 0 : bmp_mem = plt_zmalloc(bmp_sz * NIX_TXSCH_LVL_CNT * 2, 0);
1949 [ # # ]: 0 : if (!bmp_mem)
1950 : : return rc;
1951 : 0 : nix->schq_bmp_mem = bmp_mem;
1952 : :
1953 : : /* Init contiguous and discontiguous bitmap per lvl */
1954 : : rc = -EIO;
1955 [ # # ]: 0 : for (hw_lvl = 0; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
1956 : : /* Bitmap for discontiguous resource */
1957 : 0 : nix->schq_bmp[hw_lvl] =
1958 : 0 : plt_bitmap_init(NIX_TM_MAX_HW_TXSCHQ, bmp_mem, bmp_sz);
1959 [ # # ]: 0 : if (!nix->schq_bmp[hw_lvl])
1960 : 0 : goto exit;
1961 : :
1962 : 0 : bmp_mem = PLT_PTR_ADD(bmp_mem, bmp_sz);
1963 : :
1964 : : /* Bitmap for contiguous resource */
1965 : 0 : nix->schq_contig_bmp[hw_lvl] =
1966 : 0 : plt_bitmap_init(NIX_TM_MAX_HW_TXSCHQ, bmp_mem, bmp_sz);
1967 [ # # ]: 0 : if (!nix->schq_contig_bmp[hw_lvl])
1968 : 0 : goto exit;
1969 : :
1970 : 0 : bmp_mem = PLT_PTR_ADD(bmp_mem, bmp_sz);
1971 : : }
1972 : :
1973 : 0 : rc = nix_tm_mark_init(nix);
1974 [ # # ]: 0 : if (rc)
1975 : 0 : goto exit;
1976 : :
1977 : : /* Disable TL1 Static Priority when VF's are enabled
1978 : : * as otherwise VF's TL2 reallocation will be needed
1979 : : * runtime to support a specific topology of PF.
1980 : : */
1981 [ # # ]: 0 : if (nix->pci_dev->max_vfs)
1982 : 0 : nix->tm_flags |= NIX_TM_TL1_NO_SP;
1983 : :
1984 : : /* TL1 access is only for PF's */
1985 [ # # ]: 0 : if (roc_nix_is_pf(roc_nix)) {
1986 : 0 : nix->tm_flags |= NIX_TM_TL1_ACCESS;
1987 : 0 : nix->tm_root_lvl = NIX_TXSCH_LVL_TL1;
1988 : : } else {
1989 : 0 : nix->tm_root_lvl = NIX_TXSCH_LVL_TL2;
1990 : : }
1991 : :
1992 : : return 0;
1993 : 0 : exit:
1994 : 0 : nix_tm_conf_fini(roc_nix);
1995 : 0 : return rc;
1996 : : }
1997 : :
1998 : : void
1999 : 0 : nix_tm_conf_fini(struct roc_nix *roc_nix)
2000 : : {
2001 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
2002 : : uint16_t hw_lvl;
2003 : :
2004 : : for (hw_lvl = 0; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
2005 : : plt_bitmap_free(nix->schq_bmp[hw_lvl]);
2006 : : plt_bitmap_free(nix->schq_contig_bmp[hw_lvl]);
2007 : : }
2008 : 0 : plt_free(nix->schq_bmp_mem);
2009 : 0 : }
|