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