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 : : int
9 : 0 : roc_nix_tm_sq_aura_fc(struct roc_nix_sq *sq, bool enable)
10 : : {
11 : : struct npa_aq_enq_req *req;
12 : : struct npa_aq_enq_rsp *rsp;
13 : : uint64_t aura_handle;
14 : : struct npa_lf *lf;
15 : : struct mbox *mbox;
16 : : int rc = -ENOSPC;
17 : :
18 [ # # ]: 0 : plt_tm_dbg("Setting SQ %u SQB aura FC to %s", sq->qid,
19 : : enable ? "enable" : "disable");
20 : :
21 : 0 : lf = idev_npa_obj_get();
22 [ # # ]: 0 : if (!lf)
23 : : return NPA_ERR_DEVICE_NOT_BOUNDED;
24 : :
25 : 0 : mbox = mbox_get(lf->mbox);
26 : : /* Set/clear sqb aura fc_ena */
27 : 0 : aura_handle = sq->aura_handle;
28 : 0 : req = mbox_alloc_msg_npa_aq_enq(mbox);
29 [ # # ]: 0 : if (req == NULL)
30 : 0 : goto exit;
31 : :
32 : 0 : req->aura_id = roc_npa_aura_handle_to_aura(aura_handle);
33 : 0 : req->ctype = NPA_AQ_CTYPE_AURA;
34 : 0 : req->op = NPA_AQ_INSTOP_WRITE;
35 : : /* Below is not needed for aura writes but AF driver needs it */
36 : : /* AF will translate to associated poolctx */
37 : 0 : req->aura.pool_addr = req->aura_id;
38 : :
39 : 0 : req->aura.fc_ena = enable;
40 [ # # ]: 0 : req->aura_mask.fc_ena = 1;
41 [ # # # # ]: 0 : if (roc_model_is_cn9k() || roc_errata_npa_has_no_fc_stype_ststp()) {
42 : 0 : req->aura.fc_stype = 0x0; /* STF */
43 : 0 : req->aura_mask.fc_stype = 0x0; /* STF */
44 : : } else {
45 : 0 : req->aura.fc_stype = 0x3; /* STSTP */
46 : 0 : req->aura_mask.fc_stype = 0x3; /* STSTP */
47 : : }
48 : :
49 : 0 : rc = mbox_process(mbox);
50 [ # # ]: 0 : if (rc)
51 : 0 : goto exit;
52 : :
53 : : /* Read back npa aura ctx */
54 [ # # ]: 0 : if (enable) {
55 : 0 : req = mbox_alloc_msg_npa_aq_enq(mbox);
56 [ # # ]: 0 : if (req == NULL) {
57 : : rc = -ENOSPC;
58 : 0 : goto exit;
59 : : }
60 : :
61 : 0 : req->aura_id = roc_npa_aura_handle_to_aura(aura_handle);
62 : 0 : req->ctype = NPA_AQ_CTYPE_AURA;
63 : 0 : req->op = NPA_AQ_INSTOP_READ;
64 : :
65 : : rc = mbox_process_msg(mbox, (void *)&rsp);
66 [ # # ]: 0 : if (rc)
67 : 0 : goto exit;
68 : :
69 : : /* Init when enabled as there might be no triggers */
70 : 0 : *(volatile uint64_t *)sq->fc = rsp->aura.count;
71 : : } else {
72 : 0 : *(volatile uint64_t *)sq->fc = sq->aura_sqb_bufs;
73 : : }
74 : : /* Sync write barrier */
75 : : plt_wmb();
76 : : rc = 0;
77 : 0 : exit:
78 : : mbox_put(mbox);
79 : 0 : return rc;
80 : : }
81 : :
82 : : int
83 : 0 : roc_nix_tm_free_resources(struct roc_nix *roc_nix, bool hw_only)
84 : : {
85 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
86 : :
87 [ # # ]: 0 : if (nix->tm_flags & NIX_TM_HIERARCHY_ENA)
88 : : return -EBUSY;
89 : :
90 : 0 : return nix_tm_free_resources(roc_nix, BIT(ROC_NIX_TM_USER), hw_only);
91 : : }
92 : :
93 : : static int
94 : 0 : nix_tm_adjust_shaper_pps_rate(struct nix_tm_shaper_profile *profile)
95 : : {
96 : 0 : uint64_t min_rate = profile->commit.rate;
97 : :
98 [ # # ]: 0 : if (!profile->pkt_mode)
99 : : return 0;
100 : :
101 : 0 : profile->pkt_mode_adj = 1;
102 : :
103 [ # # ]: 0 : if (profile->commit.rate &&
104 : : (profile->commit.rate < NIX_TM_MIN_SHAPER_PPS_RATE ||
105 : : profile->commit.rate > NIX_TM_MAX_SHAPER_PPS_RATE))
106 : : return NIX_ERR_TM_INVALID_COMMIT_RATE;
107 : :
108 [ # # ]: 0 : if (profile->peak.rate &&
109 : : (profile->peak.rate < NIX_TM_MIN_SHAPER_PPS_RATE ||
110 : : profile->peak.rate > NIX_TM_MAX_SHAPER_PPS_RATE))
111 : : return NIX_ERR_TM_INVALID_PEAK_RATE;
112 : :
113 [ # # ]: 0 : if (profile->peak.rate && min_rate > profile->peak.rate)
114 : : min_rate = profile->peak.rate;
115 : :
116 : : /* Each packet accumulate single count, whereas HW
117 : : * considers each unit as Byte, so we need convert
118 : : * user pps to bps
119 : : */
120 : 0 : profile->commit.rate = profile->commit.rate * 8;
121 : 0 : profile->peak.rate = profile->peak.rate * 8;
122 : 0 : min_rate = min_rate * 8;
123 : :
124 [ # # ]: 0 : if (min_rate && (min_rate < NIX_TM_MIN_SHAPER_RATE)) {
125 : 0 : int adjust = NIX_TM_MIN_SHAPER_RATE / min_rate;
126 : :
127 : : if (adjust > NIX_TM_LENGTH_ADJUST_MAX)
128 : : return NIX_ERR_TM_SHAPER_PKT_LEN_ADJUST;
129 : :
130 : 0 : profile->pkt_mode_adj += adjust;
131 : 0 : profile->commit.rate += (adjust * profile->commit.rate);
132 : 0 : profile->peak.rate += (adjust * profile->peak.rate);
133 : : /* Number of tokens freed after scheduling was proportional
134 : : * to adjust value
135 : : */
136 : 0 : profile->commit.size *= adjust;
137 : 0 : profile->peak.size *= adjust;
138 : : }
139 : :
140 : : return 0;
141 : : }
142 : :
143 : : static int
144 : 0 : nix_tm_shaper_profile_add(struct roc_nix *roc_nix,
145 : : struct nix_tm_shaper_profile *profile, int skip_ins)
146 : : {
147 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
148 : : uint64_t commit_rate, commit_sz;
149 : : uint64_t min_burst, max_burst;
150 : : uint64_t peak_rate, peak_sz;
151 : : uint32_t id;
152 : : int rc;
153 : :
154 : 0 : id = profile->id;
155 : 0 : rc = nix_tm_adjust_shaper_pps_rate(profile);
156 [ # # ]: 0 : if (rc)
157 : : return rc;
158 : :
159 : 0 : commit_rate = profile->commit.rate;
160 : 0 : commit_sz = profile->commit.size;
161 : 0 : peak_rate = profile->peak.rate;
162 [ # # ]: 0 : peak_sz = profile->peak.size;
163 : :
164 : : min_burst = NIX_TM_MIN_SHAPER_BURST;
165 : : max_burst = roc_nix_tm_max_shaper_burst_get();
166 : :
167 [ # # # # ]: 0 : if (nix_tm_shaper_profile_search(nix, id) && !skip_ins)
168 : : return NIX_ERR_TM_SHAPER_PROFILE_EXISTS;
169 : :
170 [ # # ]: 0 : if (profile->pkt_len_adj < NIX_TM_LENGTH_ADJUST_MIN ||
171 : : profile->pkt_len_adj > NIX_TM_LENGTH_ADJUST_MAX)
172 : : return NIX_ERR_TM_SHAPER_PKT_LEN_ADJUST;
173 : :
174 : : /* We cannot support both pkt length adjust and pkt mode */
175 [ # # # # ]: 0 : if (profile->pkt_mode && profile->pkt_len_adj)
176 : : return NIX_ERR_TM_SHAPER_PKT_LEN_ADJUST;
177 : :
178 : : /* commit rate and burst size can be enabled/disabled */
179 [ # # ]: 0 : if (commit_rate || commit_sz) {
180 [ # # ]: 0 : if (commit_sz < min_burst || commit_sz > max_burst)
181 : : return NIX_ERR_TM_INVALID_COMMIT_SZ;
182 [ # # ]: 0 : else if (!nix_tm_shaper_rate_conv(commit_rate, NULL, NULL, NULL,
183 : 0 : profile->accuracy))
184 : : return NIX_ERR_TM_INVALID_COMMIT_RATE;
185 : : }
186 : :
187 : : /* Peak rate and burst size can be enabled/disabled */
188 [ # # ]: 0 : if (peak_sz || peak_rate) {
189 [ # # ]: 0 : if (peak_sz < min_burst || peak_sz > max_burst)
190 : : return NIX_ERR_TM_INVALID_PEAK_SZ;
191 [ # # ]: 0 : else if (!nix_tm_shaper_rate_conv(peak_rate, NULL, NULL, NULL,
192 : 0 : profile->accuracy))
193 : : return NIX_ERR_TM_INVALID_PEAK_RATE;
194 : : }
195 : :
196 : : /* If PIR and CIR are requested, PIR should always be larger than CIR */
197 [ # # # # ]: 0 : if (peak_rate && commit_rate && (commit_rate > peak_rate))
198 : : return NIX_ERR_TM_INVALID_PEAK_RATE;
199 : :
200 [ # # ]: 0 : if (!skip_ins)
201 : 0 : TAILQ_INSERT_TAIL(&nix->shaper_profile_list, profile, shaper);
202 : :
203 : 0 : plt_tm_dbg("Added TM shaper profile %u, "
204 : : " pir %" PRIu64 " , pbs %" PRIu64 ", cir %" PRIu64
205 : : ", cbs %" PRIu64 " , adj %u, pkt_mode %u",
206 : : id, profile->peak.rate, profile->peak.size,
207 : : profile->commit.rate, profile->commit.size,
208 : : profile->pkt_len_adj, profile->pkt_mode);
209 : :
210 : : /* Always use PIR for single rate shaping */
211 [ # # ]: 0 : if (!peak_rate && commit_rate) {
212 : 0 : profile->peak.rate = profile->commit.rate;
213 : 0 : profile->peak.size = profile->commit.size;
214 : 0 : profile->commit.rate = 0;
215 : 0 : profile->commit.size = 0;
216 : : }
217 : :
218 : : /* update min rate */
219 : 0 : nix->tm_rate_min = nix_tm_shaper_profile_rate_min(nix);
220 : 0 : return 0;
221 : : }
222 : :
223 : : int
224 : 0 : roc_nix_tm_shaper_profile_add(struct roc_nix *roc_nix,
225 : : struct roc_nix_tm_shaper_profile *roc_profile)
226 : : {
227 : : struct nix_tm_shaper_profile *profile;
228 : :
229 : 0 : profile = (struct nix_tm_shaper_profile *)roc_profile->reserved;
230 : :
231 : 0 : profile->ref_cnt = 0;
232 : 0 : profile->id = roc_profile->id;
233 : 0 : profile->commit.rate = roc_profile->commit_rate;
234 : 0 : profile->peak.rate = roc_profile->peak_rate;
235 : 0 : profile->commit.size = roc_profile->commit_sz;
236 : 0 : profile->peak.size = roc_profile->peak_sz;
237 : 0 : profile->pkt_len_adj = roc_profile->pkt_len_adj;
238 : 0 : profile->pkt_mode = roc_profile->pkt_mode;
239 : 0 : profile->free_fn = roc_profile->free_fn;
240 : 0 : profile->accuracy = roc_profile->accuracy;
241 : :
242 : 0 : return nix_tm_shaper_profile_add(roc_nix, profile, 0);
243 : : }
244 : :
245 : : int
246 : 0 : roc_nix_tm_shaper_profile_update(struct roc_nix *roc_nix,
247 : : struct roc_nix_tm_shaper_profile *roc_profile)
248 : : {
249 : : struct nix_tm_shaper_profile *profile;
250 : :
251 : 0 : profile = (struct nix_tm_shaper_profile *)roc_profile->reserved;
252 : :
253 : 0 : profile->commit.rate = roc_profile->commit_rate;
254 : 0 : profile->peak.rate = roc_profile->peak_rate;
255 : 0 : profile->commit.size = roc_profile->commit_sz;
256 : 0 : profile->peak.size = roc_profile->peak_sz;
257 : 0 : profile->pkt_len_adj = roc_profile->pkt_len_adj;
258 : 0 : profile->accuracy = roc_profile->accuracy;
259 : :
260 : 0 : return nix_tm_shaper_profile_add(roc_nix, profile, 1);
261 : : }
262 : :
263 : : int
264 : 0 : roc_nix_tm_shaper_profile_delete(struct roc_nix *roc_nix, uint32_t id)
265 : : {
266 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
267 : : struct nix_tm_shaper_profile *profile;
268 : :
269 : 0 : profile = nix_tm_shaper_profile_search(nix, id);
270 [ # # ]: 0 : if (!profile)
271 : : return NIX_ERR_TM_INVALID_SHAPER_PROFILE;
272 : :
273 [ # # ]: 0 : if (profile->ref_cnt)
274 : : return NIX_ERR_TM_SHAPER_PROFILE_IN_USE;
275 : :
276 : 0 : plt_tm_dbg("Removing TM shaper profile %u", id);
277 [ # # ]: 0 : TAILQ_REMOVE(&nix->shaper_profile_list, profile, shaper);
278 : 0 : nix_tm_shaper_profile_free(profile);
279 : :
280 : : /* update min rate */
281 : 0 : nix->tm_rate_min = nix_tm_shaper_profile_rate_min(nix);
282 : 0 : return 0;
283 : : }
284 : :
285 : : int
286 : 0 : roc_nix_tm_node_add(struct roc_nix *roc_nix, struct roc_nix_tm_node *roc_node)
287 : : {
288 : : struct nix_tm_node *node;
289 : :
290 : 0 : node = (struct nix_tm_node *)&roc_node->reserved;
291 : 0 : node->id = roc_node->id;
292 : 0 : node->priority = roc_node->priority;
293 : 0 : node->weight = roc_node->weight;
294 : 0 : node->lvl = roc_node->lvl;
295 : 0 : node->parent_id = roc_node->parent_id;
296 : 0 : node->shaper_profile_id = roc_node->shaper_profile_id;
297 : 0 : node->pkt_mode = roc_node->pkt_mode;
298 : 0 : node->pkt_mode_set = roc_node->pkt_mode_set;
299 : 0 : node->free_fn = roc_node->free_fn;
300 : 0 : node->tree = ROC_NIX_TM_USER;
301 : 0 : node->rel_chan = NIX_TM_CHAN_INVALID;
302 : :
303 : 0 : return nix_tm_node_add(roc_nix, node);
304 : : }
305 : :
306 : : int
307 : 0 : roc_nix_tm_node_pkt_mode_update(struct roc_nix *roc_nix, uint32_t node_id,
308 : : bool pkt_mode)
309 : : {
310 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
311 : : struct nix_tm_node *node, *child;
312 : : struct nix_tm_node_list *list;
313 : : int num_children = 0;
314 : :
315 : 0 : node = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);
316 [ # # ]: 0 : if (!node)
317 : : return NIX_ERR_TM_INVALID_NODE;
318 : :
319 [ # # ]: 0 : if (node->pkt_mode == pkt_mode) {
320 : 0 : node->pkt_mode_set = true;
321 : 0 : return 0;
322 : : }
323 : :
324 : : /* Check for any existing children, if there are any,
325 : : * then we cannot update the pkt mode as children's quantum
326 : : * are already taken in.
327 : : */
328 : : list = nix_tm_node_list(nix, ROC_NIX_TM_USER);
329 [ # # ]: 0 : TAILQ_FOREACH(child, list, node) {
330 [ # # ]: 0 : if (child->parent == node)
331 : 0 : num_children++;
332 : : }
333 : :
334 : : /* Cannot update mode if it has children or tree is enabled */
335 [ # # # # ]: 0 : if ((nix->tm_flags & NIX_TM_HIERARCHY_ENA) && num_children)
336 : : return -EBUSY;
337 : :
338 [ # # # # ]: 0 : if (node->pkt_mode_set && num_children)
339 : : return NIX_ERR_TM_PKT_MODE_MISMATCH;
340 : :
341 : 0 : node->pkt_mode = pkt_mode;
342 : 0 : node->pkt_mode_set = true;
343 : :
344 : 0 : return 0;
345 : : }
346 : :
347 : : int
348 : 0 : roc_nix_tm_node_name_get(struct roc_nix *roc_nix, uint32_t node_id, char *buf,
349 : : size_t buflen)
350 : : {
351 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
352 : : struct nix_tm_node *node;
353 : :
354 : 0 : node = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);
355 [ # # ]: 0 : if (!node) {
356 : : plt_strlcpy(buf, "???", buflen);
357 : 0 : return NIX_ERR_TM_INVALID_NODE;
358 : : }
359 : :
360 [ # # ]: 0 : if (node->hw_lvl == NIX_TXSCH_LVL_CNT)
361 : 0 : snprintf(buf, buflen, "SQ_%d", node->id);
362 : : else
363 [ # # # # : 0 : snprintf(buf, buflen, "%s_%d", nix_tm_hwlvl2str(node->hw_lvl),
# # ]
364 : : node->hw_id);
365 : : return 0;
366 : : }
367 : :
368 : : int
369 : 0 : roc_nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id, bool free)
370 : : {
371 : 0 : return nix_tm_node_delete(roc_nix, node_id, ROC_NIX_TM_USER, free);
372 : : }
373 : :
374 : : int
375 [ # # ]: 0 : roc_nix_smq_flush(struct roc_nix *roc_nix)
376 : : {
377 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
378 : : struct nix_tm_node_list *list;
379 : : enum roc_nix_tm_tree tree;
380 : : struct nix_tm_node *node;
381 : : int rc = 0;
382 : :
383 [ # # ]: 0 : if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
384 : : return 0;
385 : :
386 : 0 : tree = nix->tm_tree;
387 : : list = nix_tm_node_list(nix, tree);
388 : :
389 : : /* XOFF & Flush all SMQ's. HRM mandates
390 : : * all SQ's empty before SMQ flush is issued.
391 : : */
392 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
393 [ # # ]: 0 : if (node->hw_lvl != NIX_TXSCH_LVL_SMQ)
394 : 0 : continue;
395 [ # # ]: 0 : if (!(node->flags & NIX_TM_NODE_HWRES))
396 : 0 : continue;
397 : :
398 : 0 : rc = nix_tm_smq_xoff(nix, node, true);
399 [ # # ]: 0 : if (rc) {
400 : 0 : plt_err("Failed to enable smq %u, rc=%d", node->hw_id,
401 : : rc);
402 : 0 : goto exit;
403 : : }
404 : : }
405 : :
406 : : /* XON all SMQ's */
407 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
408 [ # # ]: 0 : if (node->hw_lvl != NIX_TXSCH_LVL_SMQ)
409 : 0 : continue;
410 [ # # ]: 0 : if (!(node->flags & NIX_TM_NODE_HWRES))
411 : 0 : continue;
412 : :
413 : 0 : rc = nix_tm_smq_xoff(nix, node, false);
414 [ # # ]: 0 : if (rc) {
415 : 0 : plt_err("Failed to enable smq %u, rc=%d", node->hw_id,
416 : : rc);
417 : 0 : goto exit;
418 : : }
419 : : }
420 : 0 : exit:
421 : : return rc;
422 : : }
423 : :
424 : : int
425 [ # # ]: 0 : roc_nix_tm_hierarchy_disable(struct roc_nix *roc_nix)
426 : : {
427 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
428 : : uint16_t sqb_cnt, head_off, tail_off;
429 : 0 : uint16_t sq_cnt = nix->nb_tx_queues;
430 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
431 : : struct nix_tm_node_list *list;
432 : : enum roc_nix_tm_tree tree;
433 : : struct nix_tm_node *node;
434 : : struct roc_nix_sq *sq;
435 : : uint64_t wdata, val;
436 : : uintptr_t regaddr;
437 : : int rc = -1, i;
438 : :
439 [ # # ]: 0 : if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
440 : : return 0;
441 : :
442 : 0 : plt_tm_dbg("Disabling hierarchy on %s", nix->pci_dev->name);
443 : :
444 : 0 : tree = nix->tm_tree;
445 : : list = nix_tm_node_list(nix, tree);
446 : :
447 : : /* Enable CGX RXTX to drain pkts */
448 [ # # ]: 0 : if (!roc_nix->io_enabled) {
449 : : /* Though it enables both RX MCAM Entries and CGX Link
450 : : * we assume all the rx queues are stopped way back.
451 : : */
452 : 0 : mbox_alloc_msg_nix_lf_start_rx(mbox_get(mbox));
453 : 0 : rc = mbox_process(mbox);
454 [ # # ]: 0 : if (rc) {
455 : : mbox_put(mbox);
456 : 0 : plt_err("cgx start failed, rc=%d", rc);
457 : 0 : return rc;
458 : : }
459 : : mbox_put(mbox);
460 : : }
461 : :
462 : : /* XON all SMQ's */
463 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
464 [ # # ]: 0 : if (node->hw_lvl != NIX_TXSCH_LVL_SMQ)
465 : 0 : continue;
466 [ # # ]: 0 : if (!(node->flags & NIX_TM_NODE_HWRES))
467 : 0 : continue;
468 : :
469 : 0 : rc = nix_tm_smq_xoff(nix, node, false);
470 [ # # ]: 0 : if (rc) {
471 : 0 : plt_err("Failed to enable smq %u, rc=%d", node->hw_id,
472 : : rc);
473 : 0 : goto cleanup;
474 : : }
475 : : }
476 : :
477 : : /* Disable backpressure, it will be enabled back if needed on
478 : : * hierarchy enable
479 : : */
480 [ # # ]: 0 : for (i = 0; i < sq_cnt; i++) {
481 : 0 : sq = nix->sqs[i];
482 [ # # ]: 0 : if (!sq)
483 : 0 : continue;
484 : :
485 : 0 : rc = nix_tm_bp_config_set(roc_nix, sq->qid, 0, false);
486 [ # # ]: 0 : if (rc && rc != -ENOENT) {
487 : 0 : plt_err("Failed to disable backpressure, rc=%d", rc);
488 : 0 : goto cleanup;
489 : : }
490 : : }
491 : :
492 : : /* Flush all tx queues */
493 [ # # ]: 0 : for (i = 0; i < sq_cnt; i++) {
494 : 0 : sq = nix->sqs[i];
495 [ # # ]: 0 : if (!sq)
496 : 0 : continue;
497 : :
498 : 0 : rc = roc_nix_sq_ena_dis(sq, false);
499 [ # # ]: 0 : if (rc) {
500 : 0 : plt_err("Failed to disable sqb aura fc, rc=%d", rc);
501 : 0 : goto cleanup;
502 : : }
503 : :
504 : : /* Wait for sq entries to be flushed */
505 : 0 : rc = roc_nix_tm_sq_flush_spin(sq);
506 [ # # ]: 0 : if (rc) {
507 : 0 : plt_err("Failed to drain sq, rc=%d\n", rc);
508 : 0 : goto cleanup;
509 : : }
510 : : }
511 : :
512 : : /* XOFF & Flush all SMQ's. HRM mandates
513 : : * all SQ's empty before SMQ flush is issued.
514 : : */
515 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
516 [ # # ]: 0 : if (node->hw_lvl != NIX_TXSCH_LVL_SMQ)
517 : 0 : continue;
518 [ # # ]: 0 : if (!(node->flags & NIX_TM_NODE_HWRES))
519 : 0 : continue;
520 : :
521 : 0 : rc = nix_tm_smq_xoff(nix, node, true);
522 [ # # ]: 0 : if (rc) {
523 : 0 : plt_err("Failed to enable smq %u, rc=%d", node->hw_id,
524 : : rc);
525 : 0 : goto cleanup;
526 : : }
527 : :
528 : 0 : node->flags &= ~NIX_TM_NODE_ENABLED;
529 : : }
530 : :
531 : : /* Verify sanity of all tx queues */
532 [ # # ]: 0 : for (i = 0; i < sq_cnt; i++) {
533 : 0 : sq = nix->sqs[i];
534 [ # # ]: 0 : if (!sq)
535 : 0 : continue;
536 : :
537 : 0 : wdata = ((uint64_t)sq->qid << 32);
538 : : regaddr = nix->base + NIX_LF_SQ_OP_STATUS;
539 : : val = roc_atomic64_add_nosync(wdata, (int64_t *)regaddr);
540 : :
541 : : sqb_cnt = val & 0xFFFF;
542 : : head_off = (val >> 20) & 0x3F;
543 : : tail_off = (val >> 28) & 0x3F;
544 : :
545 : 0 : if (sqb_cnt > 1 || head_off != tail_off ||
546 [ # # ]: 0 : (*(uint64_t *)sq->fc != sq->aura_sqb_bufs))
547 : 0 : plt_err("Failed to gracefully flush sq %u", sq->qid);
548 : : }
549 : :
550 : 0 : nix->tm_flags &= ~NIX_TM_HIERARCHY_ENA;
551 : 0 : cleanup:
552 : : /* Restore cgx state */
553 [ # # ]: 0 : if (!roc_nix->io_enabled) {
554 : 0 : mbox_alloc_msg_nix_lf_stop_rx(mbox_get(mbox));
555 : 0 : rc |= mbox_process(mbox);
556 : : mbox_put(mbox);
557 : : }
558 : : return rc;
559 : : }
560 : :
561 : : int
562 [ # # ]: 0 : roc_nix_tm_hierarchy_xmit_enable(struct roc_nix *roc_nix, enum roc_nix_tm_tree tree)
563 : : {
564 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
565 : : struct nix_tm_node_list *list;
566 : : struct nix_tm_node *node;
567 : : struct roc_nix_sq *sq;
568 : : uint16_t sq_id;
569 : : int rc;
570 : :
571 [ # # ]: 0 : if (tree >= ROC_NIX_TM_TREE_MAX)
572 : : return NIX_ERR_PARAM;
573 : :
574 : : list = nix_tm_node_list(nix, tree);
575 : :
576 : : /* Update SQ Sched Data while SQ is idle */
577 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
578 [ # # # # ]: 0 : if (!nix_tm_is_leaf(nix, node->lvl))
579 : 0 : continue;
580 : :
581 : 0 : rc = nix_tm_sq_sched_conf(nix, node, false);
582 [ # # ]: 0 : if (rc) {
583 : 0 : plt_err("SQ %u sched update failed, rc=%d", node->id,
584 : : rc);
585 : 0 : return rc;
586 : : }
587 : : }
588 : :
589 : : /* Finally XON all SMQ's */
590 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
591 [ # # ]: 0 : if (node->hw_lvl != NIX_TXSCH_LVL_SMQ)
592 : 0 : continue;
593 : :
594 : 0 : rc = nix_tm_smq_xoff(nix, node, false);
595 [ # # ]: 0 : if (rc) {
596 : 0 : plt_err("Failed to enable smq %u, rc=%d", node->hw_id,
597 : : rc);
598 : 0 : return rc;
599 : : }
600 : : }
601 : :
602 : : /* Enable xmit as all the topology is ready */
603 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
604 [ # # # # ]: 0 : if (!nix_tm_is_leaf(nix, node->lvl))
605 : 0 : continue;
606 : :
607 : 0 : sq_id = node->id;
608 : 0 : sq = nix->sqs[sq_id];
609 : :
610 : 0 : rc = roc_nix_sq_ena_dis(sq, true);
611 [ # # ]: 0 : if (rc) {
612 : 0 : plt_err("TM sw xon failed on SQ %u, rc=%d", node->id,
613 : : rc);
614 : 0 : return rc;
615 : : }
616 : 0 : node->flags |= NIX_TM_NODE_ENABLED;
617 : : }
618 : :
619 : : return 0;
620 : : }
621 : :
622 : : int
623 [ # # ]: 0 : roc_nix_tm_hierarchy_enable(struct roc_nix *roc_nix, enum roc_nix_tm_tree tree,
624 : : bool xmit_enable)
625 : : {
626 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
627 : : struct nix_tm_node_list *list;
628 : : struct nix_tm_node *node;
629 : : uint32_t tree_mask;
630 : : int rc;
631 : :
632 [ # # ]: 0 : if (tree >= ROC_NIX_TM_TREE_MAX)
633 : : return NIX_ERR_PARAM;
634 : :
635 [ # # ]: 0 : if (nix->tm_flags & NIX_TM_HIERARCHY_ENA) {
636 [ # # ]: 0 : if (nix->tm_tree != tree)
637 : : return -EBUSY;
638 : 0 : return 0;
639 : : }
640 : :
641 : 0 : plt_tm_dbg("Enabling hierarchy on %s, xmit_ena %u, tree %u",
642 : : nix->pci_dev->name, xmit_enable, tree);
643 : :
644 : : /* Free hw resources of other trees */
645 : : tree_mask = NIX_TM_TREE_MASK_ALL;
646 : 0 : tree_mask &= ~BIT(tree);
647 : :
648 : 0 : rc = nix_tm_free_resources(roc_nix, tree_mask, true);
649 [ # # ]: 0 : if (rc) {
650 : 0 : plt_err("failed to free resources of other trees, rc=%d", rc);
651 : 0 : return rc;
652 : : }
653 : :
654 : : /* Update active tree before starting to do anything */
655 : 0 : nix->tm_tree = tree;
656 : :
657 : 0 : nix_tm_update_parent_info(nix, tree);
658 : :
659 : 0 : rc = nix_tm_alloc_txschq(nix, tree);
660 [ # # ]: 0 : if (rc) {
661 : 0 : plt_err("TM failed to alloc tm resources=%d", rc);
662 : 0 : return rc;
663 : : }
664 : :
665 : 0 : rc = nix_tm_assign_resources(nix, tree);
666 [ # # ]: 0 : if (rc) {
667 : 0 : plt_err("TM failed to assign tm resources=%d", rc);
668 : 0 : return rc;
669 : : }
670 : :
671 : 0 : rc = nix_tm_txsch_reg_config(nix, tree);
672 [ # # ]: 0 : if (rc) {
673 : 0 : plt_err("TM failed to configure sched registers=%d", rc);
674 : 0 : return rc;
675 : : }
676 : :
677 : : list = nix_tm_node_list(nix, tree);
678 : : /* Mark all non-leaf's as enabled */
679 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
680 [ # # # # ]: 0 : if (!nix_tm_is_leaf(nix, node->lvl))
681 : 0 : node->flags |= NIX_TM_NODE_ENABLED;
682 : : }
683 : :
684 [ # # ]: 0 : if (xmit_enable)
685 : 0 : rc = roc_nix_tm_hierarchy_xmit_enable(roc_nix, tree);
686 : :
687 [ # # ]: 0 : if (!rc)
688 : 0 : nix->tm_flags |= NIX_TM_HIERARCHY_ENA;
689 : : return rc;
690 : : }
691 : :
692 : : int
693 : 0 : roc_nix_tm_node_suspend_resume(struct roc_nix *roc_nix, uint32_t node_id,
694 : : bool suspend)
695 : : {
696 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
697 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
698 : : struct nix_txschq_config *req;
699 : : struct nix_tm_node *node;
700 : : uint16_t flags;
701 : : int rc;
702 : :
703 : 0 : node = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);
704 [ # # ]: 0 : if (!node)
705 : : return NIX_ERR_TM_INVALID_NODE;
706 : :
707 : 0 : flags = node->flags;
708 [ # # ]: 0 : flags = suspend ? (flags & ~NIX_TM_NODE_ENABLED) :
709 : : (flags | NIX_TM_NODE_ENABLED);
710 : :
711 [ # # ]: 0 : if (node->flags == flags)
712 : : return 0;
713 : :
714 : : /* send mbox for state change */
715 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
716 : :
717 : 0 : req->lvl = node->hw_lvl;
718 : 0 : req->num_regs =
719 : 0 : nix_tm_sw_xoff_prep(node, suspend, req->reg, req->regval);
720 : 0 : rc = mbox_process(mbox);
721 : : mbox_put(mbox);
722 [ # # ]: 0 : if (!rc)
723 : 0 : node->flags = flags;
724 : : return rc;
725 : : }
726 : :
727 : : int
728 : 0 : roc_nix_tm_prealloc_res(struct roc_nix *roc_nix, uint8_t lvl,
729 : : uint16_t discontig, uint16_t contig)
730 : : {
731 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
732 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
733 : : struct nix_txsch_alloc_req *req;
734 : : struct nix_txsch_alloc_rsp *rsp;
735 : : uint8_t hw_lvl;
736 : : int rc = -ENOSPC;
737 : :
738 : 0 : hw_lvl = nix_tm_lvl2nix(nix, lvl);
739 [ # # ]: 0 : if (hw_lvl == NIX_TXSCH_LVL_CNT)
740 : : return -EINVAL;
741 : :
742 : : /* Preallocate contiguous */
743 [ # # ]: 0 : if (nix->contig_rsvd[hw_lvl] < contig) {
744 : 0 : req = mbox_alloc_msg_nix_txsch_alloc(mbox_get(mbox));
745 [ # # ]: 0 : if (req == NULL) {
746 : : mbox_put(mbox);
747 : 0 : return rc;
748 : : }
749 : 0 : req->schq_contig[hw_lvl] = contig - nix->contig_rsvd[hw_lvl];
750 : :
751 : : rc = mbox_process_msg(mbox, (void *)&rsp);
752 [ # # ]: 0 : if (rc) {
753 : : mbox_put(mbox);
754 : 0 : return rc;
755 : : }
756 : :
757 : 0 : nix_tm_copy_rsp_to_nix(nix, rsp);
758 : : mbox_put(mbox);
759 : : }
760 : :
761 : : /* Preallocate contiguous */
762 [ # # ]: 0 : if (nix->discontig_rsvd[hw_lvl] < discontig) {
763 : 0 : req = mbox_alloc_msg_nix_txsch_alloc(mbox_get(mbox));
764 [ # # ]: 0 : if (req == NULL) {
765 : : mbox_put(mbox);
766 : 0 : return -ENOSPC;
767 : : }
768 : 0 : req->schq[hw_lvl] = discontig - nix->discontig_rsvd[hw_lvl];
769 : :
770 : : rc = mbox_process_msg(mbox, (void *)&rsp);
771 [ # # ]: 0 : if (rc) {
772 : : mbox_put(mbox);
773 : 0 : return rc;
774 : : }
775 : :
776 : 0 : nix_tm_copy_rsp_to_nix(nix, rsp);
777 : : mbox_put(mbox);
778 : : }
779 : :
780 : : /* Save thresholds */
781 : 0 : nix->contig_rsvd[hw_lvl] = contig;
782 : 0 : nix->discontig_rsvd[hw_lvl] = discontig;
783 : : /* Release anything present above thresholds */
784 : 0 : nix_tm_release_resources(nix, hw_lvl, true, true);
785 : 0 : nix_tm_release_resources(nix, hw_lvl, false, true);
786 : 0 : return 0;
787 : : }
788 : :
789 : : int
790 : 0 : roc_nix_tm_node_shaper_update(struct roc_nix *roc_nix, uint32_t node_id,
791 : : uint32_t profile_id, bool force_update)
792 : : {
793 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
794 : : struct nix_tm_shaper_profile *profile = NULL;
795 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
796 : : struct nix_txschq_config *req;
797 : : struct nix_tm_node *node;
798 : : uint8_t k;
799 : : int rc;
800 : :
801 : : /* Shaper updates valid only for user nodes */
802 : 0 : node = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);
803 [ # # # # : 0 : if (!node || nix_tm_is_leaf(nix, node->lvl))
# # ]
804 : : return NIX_ERR_TM_INVALID_NODE;
805 : :
806 [ # # ]: 0 : if (profile_id != ROC_NIX_TM_SHAPER_PROFILE_NONE) {
807 : 0 : profile = nix_tm_shaper_profile_search(nix, profile_id);
808 [ # # ]: 0 : if (!profile)
809 : : return NIX_ERR_TM_INVALID_SHAPER_PROFILE;
810 : : }
811 : :
812 : : /* Pkt mode should match existing node's pkt mode */
813 [ # # ]: 0 : if (profile && profile->pkt_mode != node->pkt_mode)
814 : : return NIX_ERR_TM_PKT_MODE_MISMATCH;
815 : :
816 [ # # # # ]: 0 : if ((profile_id == node->shaper_profile_id) && !force_update) {
817 : : return 0;
818 [ # # ]: 0 : } else if (profile_id != node->shaper_profile_id) {
819 : : struct nix_tm_shaper_profile *old;
820 : :
821 : : /* Find old shaper profile and reduce ref count */
822 : 0 : old = nix_tm_shaper_profile_search(nix,
823 : : node->shaper_profile_id);
824 [ # # ]: 0 : if (old)
825 : 0 : old->ref_cnt--;
826 : :
827 [ # # ]: 0 : if (profile)
828 : 0 : profile->ref_cnt++;
829 : :
830 : : /* Reduce older shaper ref count and increase new one */
831 : 0 : node->shaper_profile_id = profile_id;
832 : : }
833 : :
834 : : /* Nothing to do if hierarchy not yet enabled */
835 [ # # ]: 0 : if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
836 : : return 0;
837 : :
838 : 0 : node->flags &= ~NIX_TM_NODE_ENABLED;
839 : :
840 : : /* Flush the specific node with SW_XOFF */
841 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
842 : 0 : req->lvl = node->hw_lvl;
843 : 0 : k = nix_tm_sw_xoff_prep(node, true, req->reg, req->regval);
844 : 0 : req->num_regs = k;
845 : :
846 : 0 : rc = mbox_process(mbox);
847 [ # # ]: 0 : if (rc) {
848 : : mbox_put(mbox);
849 : 0 : return rc;
850 : : }
851 : : mbox_put(mbox);
852 : :
853 : : /* Update the PIR/CIR and clear SW XOFF */
854 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
855 : 0 : req->lvl = node->hw_lvl;
856 : :
857 : 0 : k = nix_tm_shaper_reg_prep(node, profile, req->reg, req->regval);
858 : :
859 : 0 : k += nix_tm_sw_xoff_prep(node, false, &req->reg[k], &req->regval[k]);
860 : :
861 : 0 : req->num_regs = k;
862 : 0 : rc = mbox_process(mbox);
863 : : mbox_put(mbox);
864 [ # # ]: 0 : if (!rc)
865 : 0 : node->flags |= NIX_TM_NODE_ENABLED;
866 : : return rc;
867 : : }
868 : :
869 : : int
870 : 0 : roc_nix_tm_node_parent_update(struct roc_nix *roc_nix, uint32_t node_id,
871 : : uint32_t new_parent_id, uint32_t priority,
872 : : uint32_t weight)
873 : : {
874 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
875 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
876 : : struct nix_tm_node *node, *sibling;
877 : : struct nix_tm_node *new_parent;
878 : : struct nix_txschq_config *req;
879 : : struct nix_tm_node_list *list;
880 : : uint8_t k;
881 : : int rc;
882 : :
883 : 0 : node = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);
884 [ # # ]: 0 : if (!node)
885 : : return NIX_ERR_TM_INVALID_NODE;
886 : :
887 : : /* Parent id valid only for non root nodes */
888 [ # # ]: 0 : if (node->hw_lvl != nix->tm_root_lvl) {
889 : : new_parent =
890 : 0 : nix_tm_node_search(nix, new_parent_id, ROC_NIX_TM_USER);
891 [ # # ]: 0 : if (!new_parent)
892 : : return NIX_ERR_TM_INVALID_PARENT;
893 : :
894 : : /* Current support is only for dynamic weight update */
895 [ # # # # ]: 0 : if (node->parent != new_parent || node->priority != priority)
896 : : return NIX_ERR_TM_PARENT_PRIO_UPDATE;
897 : : }
898 : :
899 : : list = nix_tm_node_list(nix, ROC_NIX_TM_USER);
900 : : /* Skip if no change */
901 [ # # ]: 0 : if (node->weight == weight)
902 : : return 0;
903 : :
904 : 0 : node->weight = weight;
905 : :
906 : : /* Nothing to do if hierarchy not yet enabled */
907 [ # # ]: 0 : if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
908 : : return 0;
909 : :
910 : : /* For leaf nodes, SQ CTX needs update */
911 [ # # # # ]: 0 : if (nix_tm_is_leaf(nix, node->lvl)) {
912 : : /* Update SQ quantum data on the fly */
913 : 0 : rc = nix_tm_sq_sched_conf(nix, node, true);
914 [ # # ]: 0 : if (rc)
915 : 0 : return NIX_ERR_TM_SQ_UPDATE_FAIL;
916 : : } else {
917 : : /* XOFF Parent node */
918 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
919 : 0 : req->lvl = node->parent->hw_lvl;
920 : 0 : req->num_regs = nix_tm_sw_xoff_prep(node->parent, true,
921 : 0 : req->reg, req->regval);
922 : 0 : rc = mbox_process(mbox);
923 : : mbox_put(mbox);
924 [ # # ]: 0 : if (rc)
925 : : return rc;
926 : :
927 : : /* XOFF this node and all other siblings */
928 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
929 : 0 : req->lvl = node->hw_lvl;
930 : :
931 : : k = 0;
932 [ # # ]: 0 : TAILQ_FOREACH(sibling, list, node) {
933 [ # # ]: 0 : if (sibling->parent != node->parent)
934 : 0 : continue;
935 : 0 : k += nix_tm_sw_xoff_prep(sibling, true, &req->reg[k], &req->regval[k]);
936 [ # # ]: 0 : if (k >= MAX_REGS_PER_MBOX_MSG) {
937 : 0 : req->num_regs = k;
938 : 0 : rc = mbox_process(mbox);
939 : : mbox_put(mbox);
940 [ # # ]: 0 : if (rc)
941 : 0 : return rc;
942 : : k = 0;
943 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
944 : 0 : req->lvl = node->hw_lvl;
945 : : }
946 : : }
947 : :
948 [ # # ]: 0 : if (k) {
949 : 0 : req->num_regs = k;
950 : 0 : rc = mbox_process(mbox);
951 : : mbox_put(mbox);
952 [ # # ]: 0 : if (rc)
953 : : return rc;
954 : : /* Update new weight for current node */
955 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
956 : : }
957 : :
958 : 0 : req->lvl = node->hw_lvl;
959 : 0 : req->num_regs = nix_tm_sched_reg_prep(nix, node, req->reg, req->regval);
960 : 0 : rc = mbox_process(mbox);
961 : : mbox_put(mbox);
962 [ # # ]: 0 : if (rc)
963 : : return rc;
964 : :
965 : : /* XON this node and all other siblings */
966 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
967 : 0 : req->lvl = node->hw_lvl;
968 : :
969 : : k = 0;
970 [ # # ]: 0 : TAILQ_FOREACH(sibling, list, node) {
971 [ # # ]: 0 : if (sibling->parent != node->parent)
972 : 0 : continue;
973 : 0 : k += nix_tm_sw_xoff_prep(sibling, false, &req->reg[k], &req->regval[k]);
974 [ # # ]: 0 : if (k >= MAX_REGS_PER_MBOX_MSG) {
975 : 0 : req->num_regs = k;
976 : 0 : rc = mbox_process(mbox);
977 : : mbox_put(mbox);
978 [ # # ]: 0 : if (rc)
979 : 0 : return rc;
980 : : k = 0;
981 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
982 : 0 : req->lvl = node->hw_lvl;
983 : : }
984 : : }
985 : :
986 [ # # ]: 0 : if (k) {
987 : 0 : req->num_regs = k;
988 : 0 : rc = mbox_process(mbox);
989 : : mbox_put(mbox);
990 [ # # ]: 0 : if (rc)
991 : : return rc;
992 : : /* XON Parent node */
993 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
994 : : }
995 : :
996 : 0 : req->lvl = node->parent->hw_lvl;
997 : 0 : req->num_regs = nix_tm_sw_xoff_prep(node->parent, false, req->reg, req->regval);
998 : 0 : rc = mbox_process(mbox);
999 : : mbox_put(mbox);
1000 [ # # ]: 0 : if (rc)
1001 : 0 : return rc;
1002 : : }
1003 : : return 0;
1004 : : }
1005 : :
1006 : : int
1007 : 0 : roc_nix_tm_init(struct roc_nix *roc_nix)
1008 : : {
1009 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1010 : : uint32_t tree_mask;
1011 : : int rc;
1012 : :
1013 [ # # ]: 0 : if (nix->tm_flags & NIX_TM_HIERARCHY_ENA) {
1014 : 0 : plt_err("Cannot init while existing hierarchy is enabled");
1015 : 0 : return -EBUSY;
1016 : : }
1017 : :
1018 : : /* Free up all user resources already held */
1019 : : tree_mask = NIX_TM_TREE_MASK_ALL;
1020 : 0 : rc = nix_tm_free_resources(roc_nix, tree_mask, false);
1021 [ # # ]: 0 : if (rc) {
1022 : 0 : plt_err("Failed to freeup all nodes and resources, rc=%d", rc);
1023 : 0 : return rc;
1024 : : }
1025 : :
1026 : : /* Prepare default tree */
1027 : 0 : rc = nix_tm_prepare_default_tree(roc_nix);
1028 [ # # ]: 0 : if (rc) {
1029 : 0 : plt_err("failed to prepare default tm tree, rc=%d", rc);
1030 : 0 : return rc;
1031 : : }
1032 : :
1033 : : return rc;
1034 : : }
1035 : :
1036 : : int
1037 [ # # ]: 0 : roc_nix_tm_pfc_rlimit_sq(struct roc_nix *roc_nix, uint16_t qid, uint64_t rate)
1038 : : {
1039 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1040 : : struct nix_tm_shaper_profile profile;
1041 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
1042 : : struct nix_tm_node *node, *parent;
1043 : : struct roc_nix_link_info link_info;
1044 : :
1045 : : volatile uint64_t *reg, *regval;
1046 : : struct nix_txschq_config *req;
1047 : : uint64_t tl2_rate = 0;
1048 : : uint16_t flags;
1049 : : uint8_t k = 0;
1050 : : int rc;
1051 : :
1052 [ # # # # ]: 0 : if ((nix->tm_tree != ROC_NIX_TM_PFC) || !(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
1053 : : return NIX_ERR_TM_INVALID_TREE;
1054 : :
1055 : 0 : node = nix_tm_node_search(nix, qid, nix->tm_tree);
1056 : :
1057 : : /* check if we found a valid leaf node */
1058 [ # # # # : 0 : if (!node || !nix_tm_is_leaf(nix, node->lvl) || !node->parent ||
# # # # ]
1059 [ # # ]: 0 : node->parent->hw_id == NIX_TM_HW_ID_INVALID) {
1060 : : return NIX_ERR_TM_INVALID_NODE;
1061 : : }
1062 : :
1063 : : /* Get the link Speed */
1064 [ # # ]: 0 : if (roc_nix_mac_link_info_get(roc_nix, &link_info))
1065 : : return -EINVAL;
1066 : :
1067 [ # # ]: 0 : if (link_info.status)
1068 : 0 : tl2_rate = link_info.speed * (uint64_t)1E6;
1069 : :
1070 : : /* Configure TL3 of leaf node with requested rate */
1071 : 0 : parent = node->parent; /* SMQ/MDQ */
1072 : 0 : parent = parent->parent; /* TL4 */
1073 : 0 : parent = parent->parent; /* TL3 */
1074 : 0 : flags = parent->flags;
1075 : :
1076 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
1077 : 0 : req->lvl = parent->hw_lvl;
1078 : 0 : reg = req->reg;
1079 : 0 : regval = req->regval;
1080 : :
1081 [ # # ]: 0 : if (rate == 0) {
1082 : 0 : k += nix_tm_sw_xoff_prep(parent, true, ®[k], ®val[k]);
1083 : 0 : flags &= ~NIX_TM_NODE_ENABLED;
1084 : 0 : goto exit;
1085 : : }
1086 : :
1087 [ # # ]: 0 : if (!(flags & NIX_TM_NODE_ENABLED)) {
1088 : 0 : k += nix_tm_sw_xoff_prep(parent, false, ®[k], ®val[k]);
1089 : 0 : flags |= NIX_TM_NODE_ENABLED;
1090 : : }
1091 : :
1092 : : /* Use only PIR for rate limit */
1093 : : memset(&profile, 0, sizeof(profile));
1094 : 0 : profile.peak.rate = rate;
1095 : : /* Minimum burst of ~4us Bytes of Tx */
1096 : 0 : profile.peak.size =
1097 : 0 : PLT_MAX((uint64_t)roc_nix_max_pkt_len(roc_nix), (4ul * rate) / ((uint64_t)1E6 * 8));
1098 [ # # # # ]: 0 : if (!nix->tm_rate_min || nix->tm_rate_min > rate)
1099 : 0 : nix->tm_rate_min = rate;
1100 : :
1101 : 0 : k += nix_tm_shaper_reg_prep(parent, &profile, ®[k], ®val[k]);
1102 : 0 : exit:
1103 : 0 : req->num_regs = k;
1104 : 0 : rc = mbox_process(mbox);
1105 : : mbox_put(mbox);
1106 [ # # ]: 0 : if (rc)
1107 : : return rc;
1108 : :
1109 : 0 : parent->flags = flags;
1110 : :
1111 : : /* If link is up then configure TL2 with link speed */
1112 [ # # # # ]: 0 : if (tl2_rate && (flags & NIX_TM_NODE_ENABLED)) {
1113 : : k = 0;
1114 : 0 : parent = parent->parent;
1115 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
1116 : 0 : req->lvl = parent->hw_lvl;
1117 : 0 : reg = req->reg;
1118 : 0 : regval = req->regval;
1119 : :
1120 : : /* Use only PIR for rate limit */
1121 : : memset(&profile, 0, sizeof(profile));
1122 : 0 : profile.peak.rate = tl2_rate;
1123 : : /* Minimum burst of ~4us Bytes of Tx */
1124 : 0 : profile.peak.size = PLT_MAX((uint64_t)roc_nix_max_pkt_len(roc_nix),
1125 : : (4ul * tl2_rate) / ((uint64_t)1E6 * 8));
1126 : 0 : k += nix_tm_shaper_reg_prep(parent, &profile, ®[k], ®val[k]);
1127 : 0 : req->num_regs = k;
1128 : 0 : rc = mbox_process(mbox);
1129 : : mbox_put(mbox);
1130 : : }
1131 : : return rc;
1132 : : }
1133 : :
1134 : : int
1135 [ # # ]: 0 : roc_nix_tm_rlimit_sq(struct roc_nix *roc_nix, uint16_t qid, uint64_t rate)
1136 : : {
1137 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1138 : : struct nix_tm_shaper_profile profile;
1139 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
1140 : : struct nix_tm_node *node, *parent;
1141 : :
1142 : : volatile uint64_t *reg, *regval;
1143 : : struct nix_txschq_config *req;
1144 : : uint16_t flags;
1145 : : uint8_t k = 0;
1146 : : int rc;
1147 : :
1148 [ # # ]: 0 : if ((nix->tm_tree == ROC_NIX_TM_USER) ||
1149 [ # # ]: 0 : !(nix->tm_flags & NIX_TM_HIERARCHY_ENA)) {
1150 : : return NIX_ERR_TM_INVALID_TREE;
1151 : : }
1152 : :
1153 : 0 : node = nix_tm_node_search(nix, qid, nix->tm_tree);
1154 : :
1155 : : /* check if we found a valid leaf node */
1156 [ # # # # : 0 : if (!node || !nix_tm_is_leaf(nix, node->lvl) || !node->parent ||
# # # # ]
1157 [ # # ]: 0 : node->parent->hw_id == NIX_TM_HW_ID_INVALID) {
1158 : : return NIX_ERR_TM_INVALID_NODE;
1159 : : }
1160 : :
1161 : : parent = node->parent;
1162 : 0 : flags = parent->flags;
1163 : :
1164 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
1165 : 0 : req->lvl = NIX_TXSCH_LVL_MDQ;
1166 : 0 : reg = req->reg;
1167 : 0 : regval = req->regval;
1168 : :
1169 [ # # ]: 0 : if (rate == 0) {
1170 : 0 : k += nix_tm_sw_xoff_prep(parent, true, ®[k], ®val[k]);
1171 : 0 : flags &= ~NIX_TM_NODE_ENABLED;
1172 : 0 : goto exit;
1173 : : }
1174 : :
1175 [ # # ]: 0 : if (!(flags & NIX_TM_NODE_ENABLED)) {
1176 : 0 : k += nix_tm_sw_xoff_prep(parent, false, ®[k], ®val[k]);
1177 : 0 : flags |= NIX_TM_NODE_ENABLED;
1178 : : }
1179 : :
1180 : : /* Use only PIR for rate limit */
1181 : : memset(&profile, 0, sizeof(profile));
1182 : 0 : profile.peak.rate = rate;
1183 : : /* Minimum burst of ~4us Bytes of Tx */
1184 : 0 : profile.peak.size = PLT_MAX((uint64_t)roc_nix_max_pkt_len(roc_nix),
1185 : : (4ul * rate) / ((uint64_t)1E6 * 8));
1186 [ # # # # ]: 0 : if (!nix->tm_rate_min || nix->tm_rate_min > rate)
1187 : 0 : nix->tm_rate_min = rate;
1188 : :
1189 : 0 : k += nix_tm_shaper_reg_prep(parent, &profile, ®[k], ®val[k]);
1190 : 0 : exit:
1191 : 0 : req->num_regs = k;
1192 : 0 : rc = mbox_process(mbox);
1193 : : mbox_put(mbox);
1194 [ # # ]: 0 : if (rc)
1195 : : return rc;
1196 : :
1197 : 0 : parent->flags = flags;
1198 : 0 : return 0;
1199 : : }
1200 : :
1201 : : void
1202 : 0 : roc_nix_tm_fini(struct roc_nix *roc_nix)
1203 : : {
1204 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1205 : 0 : struct mbox *mbox = (&nix->dev)->mbox;
1206 : : struct nix_txsch_free_req *req;
1207 : : uint32_t tree_mask;
1208 : : uint8_t hw_lvl;
1209 : : int rc;
1210 : :
1211 : : /* Xmit is assumed to be disabled */
1212 : : /* Free up resources already held */
1213 : : tree_mask = NIX_TM_TREE_MASK_ALL;
1214 : 0 : rc = nix_tm_free_resources(roc_nix, tree_mask, false);
1215 [ # # ]: 0 : if (rc)
1216 : 0 : plt_err("Failed to freeup existing nodes or rsrcs, rc=%d", rc);
1217 : :
1218 : : /* Free all other hw resources */
1219 : 0 : req = mbox_alloc_msg_nix_txsch_free(mbox_get(mbox));
1220 [ # # ]: 0 : if (req == NULL) {
1221 : : mbox_put(mbox);
1222 : 0 : return;
1223 : : }
1224 : :
1225 : 0 : req->flags = TXSCHQ_FREE_ALL;
1226 : 0 : rc = mbox_process(mbox);
1227 [ # # ]: 0 : if (rc)
1228 : 0 : plt_err("Failed to freeup all res, rc=%d", rc);
1229 : : mbox_put(mbox);
1230 : :
1231 [ # # ]: 0 : for (hw_lvl = 0; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
1232 : 0 : plt_bitmap_reset(nix->schq_bmp[hw_lvl]);
1233 : 0 : plt_bitmap_reset(nix->schq_contig_bmp[hw_lvl]);
1234 : 0 : nix->contig_rsvd[hw_lvl] = 0;
1235 : 0 : nix->discontig_rsvd[hw_lvl] = 0;
1236 : : }
1237 : :
1238 : : /* Clear shaper profiles */
1239 : 0 : nix_tm_clear_shaper_profiles(nix);
1240 : 0 : nix->tm_tree = 0;
1241 : 0 : nix->tm_flags &= ~NIX_TM_HIERARCHY_ENA;
1242 : : }
1243 : :
1244 : : int
1245 : 0 : roc_nix_tm_rsrc_count(struct roc_nix *roc_nix, uint16_t schq[ROC_TM_LVL_MAX])
1246 : : {
1247 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1248 : 0 : struct mbox *mbox = mbox_get((&nix->dev)->mbox);
1249 : : struct free_rsrcs_rsp *rsp;
1250 : : uint8_t hw_lvl;
1251 : : int rc, i;
1252 : :
1253 : : /* Get the current free resources */
1254 : 0 : mbox_alloc_msg_free_rsrc_cnt(mbox);
1255 : : rc = mbox_process_msg(mbox, (void *)&rsp);
1256 [ # # ]: 0 : if (rc)
1257 : 0 : goto exit;
1258 : :
1259 [ # # ]: 0 : for (i = 0; i < ROC_TM_LVL_MAX; i++) {
1260 : 0 : hw_lvl = nix_tm_lvl2nix(nix, i);
1261 [ # # ]: 0 : if (hw_lvl == NIX_TXSCH_LVL_CNT)
1262 : 0 : continue;
1263 : :
1264 [ # # ]: 0 : schq[i] = (nix->is_nix1 ? rsp->schq_nix1[hw_lvl] :
1265 : 0 : rsp->schq[hw_lvl]);
1266 : : }
1267 : :
1268 : : rc = 0;
1269 : 0 : exit:
1270 : : mbox_put(mbox);
1271 : 0 : return rc;
1272 : : }
1273 : :
1274 : : void
1275 : 0 : roc_nix_tm_rsrc_max(bool pf, uint16_t schq[ROC_TM_LVL_MAX])
1276 : : {
1277 : : uint8_t hw_lvl, i;
1278 : : uint16_t max;
1279 : :
1280 [ # # ]: 0 : for (i = 0; i < ROC_TM_LVL_MAX; i++) {
1281 [ # # ]: 0 : hw_lvl = pf ? nix_tm_lvl2nix_tl1_root(i) :
1282 : 0 : nix_tm_lvl2nix_tl2_root(i);
1283 : :
1284 [ # # # # : 0 : switch (hw_lvl) {
# # ]
1285 : : case NIX_TXSCH_LVL_SMQ:
1286 [ # # ]: 0 : max = (roc_model_is_cn9k() ?
1287 : : NIX_CN9K_TXSCH_LVL_SMQ_MAX :
1288 : : NIX_TXSCH_LVL_SMQ_MAX);
1289 : : break;
1290 : : case NIX_TXSCH_LVL_TL4:
1291 : : max = NIX_TXSCH_LVL_TL4_MAX;
1292 : : break;
1293 : 0 : case NIX_TXSCH_LVL_TL3:
1294 : : max = NIX_TXSCH_LVL_TL3_MAX;
1295 : 0 : break;
1296 : 0 : case NIX_TXSCH_LVL_TL2:
1297 [ # # ]: 0 : max = pf ? NIX_TXSCH_LVL_TL2_MAX : 1;
1298 : : break;
1299 : 0 : case NIX_TXSCH_LVL_TL1:
1300 : 0 : max = pf ? 1 : 0;
1301 : 0 : break;
1302 : 0 : default:
1303 : : max = 0;
1304 : 0 : break;
1305 : : }
1306 : 0 : schq[i] = max;
1307 : : }
1308 : 0 : }
1309 : :
1310 : : bool
1311 : 0 : roc_nix_tm_root_has_sp(struct roc_nix *roc_nix)
1312 : : {
1313 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix);
1314 : :
1315 [ # # ]: 0 : if (nix->tm_flags & NIX_TM_TL1_NO_SP)
1316 : 0 : return false;
1317 : : return true;
1318 : : }
1319 : :
1320 : : static inline struct nix *
1321 : 0 : pf_func_to_nix_get(uint16_t pf_func)
1322 : : {
1323 : : struct roc_nix *roc_nix_tmp = NULL;
1324 : : struct roc_nix_list *nix_list;
1325 : :
1326 : 0 : nix_list = roc_idev_nix_list_get();
1327 [ # # ]: 0 : if (nix_list == NULL)
1328 : : return NULL;
1329 : :
1330 : : /* Find the NIX of given pf_func */
1331 [ # # ]: 0 : TAILQ_FOREACH(roc_nix_tmp, nix_list, next) {
1332 : : struct nix *nix = roc_nix_to_nix_priv(roc_nix_tmp);
1333 : :
1334 [ # # ]: 0 : if (nix->dev.pf_func == pf_func)
1335 : 0 : return nix;
1336 : : }
1337 : :
1338 : : return NULL;
1339 : : }
1340 : :
1341 : : int
1342 : 0 : roc_nix_tm_egress_link_cfg_set(struct roc_nix *roc_nix, uint64_t dst_pf_func, bool enable)
1343 : : {
1344 : : struct nix *src_nix = roc_nix_to_nix_priv(roc_nix), *dst_nix;
1345 : 0 : struct mbox *mbox = (&src_nix->dev)->mbox;
1346 : : struct nix_txschq_config *req = NULL;
1347 : : struct nix_tm_node_list *list;
1348 : : struct nix_tm_node *node;
1349 : : int rc = 0, k;
1350 : :
1351 : 0 : dst_nix = pf_func_to_nix_get(dst_pf_func);
1352 [ # # ]: 0 : if (!dst_nix)
1353 : : return -EINVAL;
1354 : :
1355 [ # # ]: 0 : if (dst_nix == src_nix)
1356 : : return 0;
1357 : :
1358 : 0 : list = nix_tm_node_list(src_nix, src_nix->tm_tree);
1359 [ # # ]: 0 : TAILQ_FOREACH(node, list, node) {
1360 [ # # ]: 0 : if (node->hw_lvl != src_nix->tm_link_cfg_lvl)
1361 : 0 : continue;
1362 : :
1363 [ # # ]: 0 : if (!(node->flags & NIX_TM_NODE_HWRES))
1364 : 0 : continue;
1365 : :
1366 : : /* Allocating TL3 request */
1367 : 0 : req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox));
1368 : 0 : req->lvl = src_nix->tm_link_cfg_lvl;
1369 : : k = 0;
1370 : :
1371 : : /* Enable PFC/pause on the identified TL3 */
1372 : 0 : req->reg[k] = NIX_AF_TL3_TL2X_LINKX_CFG(node->hw_id, dst_nix->tx_link);
1373 [ # # ]: 0 : if (enable)
1374 : 0 : req->regval[k] |= BIT_ULL(12);
1375 : : else
1376 : 0 : req->regval[k] &= ~(BIT_ULL(12));
1377 : 0 : req->regval_mask[k] = ~(BIT_ULL(12));
1378 : : k++;
1379 : :
1380 : 0 : req->num_regs = k;
1381 : 0 : rc = mbox_process(mbox);
1382 : : mbox_put(mbox);
1383 [ # # ]: 0 : if (rc)
1384 : 0 : goto err;
1385 : : }
1386 : 0 : err:
1387 : : return rc;
1388 : : }
|