1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. */
3 #include <net/sch_generic.h>
4
5 #include "en.h"
6 #include "params.h"
7 #include "../qos.h"
8
9 #define BYTES_IN_MBIT 125000
10
mlx5e_qos_bytes_rate_check(struct mlx5_core_dev * mdev,u64 nbytes)11 int mlx5e_qos_bytes_rate_check(struct mlx5_core_dev *mdev, u64 nbytes)
12 {
13 if (nbytes < BYTES_IN_MBIT) {
14 qos_warn(mdev, "Input rate (%llu Bytes/sec) below minimum supported (%u Bytes/sec)\n",
15 nbytes, BYTES_IN_MBIT);
16 return -EINVAL;
17 }
18 return 0;
19 }
20
mlx5e_qos_bytes2mbits(struct mlx5_core_dev * mdev,u64 nbytes)21 static u32 mlx5e_qos_bytes2mbits(struct mlx5_core_dev *mdev, u64 nbytes)
22 {
23 return div_u64(nbytes, BYTES_IN_MBIT);
24 }
25
mlx5e_qos_max_leaf_nodes(struct mlx5_core_dev * mdev)26 int mlx5e_qos_max_leaf_nodes(struct mlx5_core_dev *mdev)
27 {
28 return min(MLX5E_QOS_MAX_LEAF_NODES, mlx5_qos_max_leaf_nodes(mdev));
29 }
30
mlx5e_qos_cur_leaf_nodes(struct mlx5e_priv * priv)31 int mlx5e_qos_cur_leaf_nodes(struct mlx5e_priv *priv)
32 {
33 int last = find_last_bit(priv->htb.qos_used_qids, mlx5e_qos_max_leaf_nodes(priv->mdev));
34
35 return last == mlx5e_qos_max_leaf_nodes(priv->mdev) ? 0 : last + 1;
36 }
37
38 /* Software representation of the QoS tree (internal to this file) */
39
mlx5e_find_unused_qos_qid(struct mlx5e_priv * priv)40 static int mlx5e_find_unused_qos_qid(struct mlx5e_priv *priv)
41 {
42 int size = mlx5e_qos_max_leaf_nodes(priv->mdev);
43 int res;
44
45 WARN_ONCE(!mutex_is_locked(&priv->state_lock), "%s: state_lock is not held\n", __func__);
46 res = find_first_zero_bit(priv->htb.qos_used_qids, size);
47
48 return res == size ? -ENOSPC : res;
49 }
50
51 struct mlx5e_qos_node {
52 struct hlist_node hnode;
53 struct mlx5e_qos_node *parent;
54 u64 rate;
55 u32 bw_share;
56 u32 max_average_bw;
57 u32 hw_id;
58 u32 classid; /* 16-bit, except root. */
59 u16 qid;
60 };
61
62 #define MLX5E_QOS_QID_INNER 0xffff
63 #define MLX5E_HTB_CLASSID_ROOT 0xffffffff
64
65 static struct mlx5e_qos_node *
mlx5e_sw_node_create_leaf(struct mlx5e_priv * priv,u16 classid,u16 qid,struct mlx5e_qos_node * parent)66 mlx5e_sw_node_create_leaf(struct mlx5e_priv *priv, u16 classid, u16 qid,
67 struct mlx5e_qos_node *parent)
68 {
69 struct mlx5e_qos_node *node;
70
71 node = kzalloc(sizeof(*node), GFP_KERNEL);
72 if (!node)
73 return ERR_PTR(-ENOMEM);
74
75 node->parent = parent;
76
77 node->qid = qid;
78 __set_bit(qid, priv->htb.qos_used_qids);
79
80 node->classid = classid;
81 hash_add_rcu(priv->htb.qos_tc2node, &node->hnode, classid);
82
83 mlx5e_update_tx_netdev_queues(priv);
84
85 return node;
86 }
87
mlx5e_sw_node_create_root(struct mlx5e_priv * priv)88 static struct mlx5e_qos_node *mlx5e_sw_node_create_root(struct mlx5e_priv *priv)
89 {
90 struct mlx5e_qos_node *node;
91
92 node = kzalloc(sizeof(*node), GFP_KERNEL);
93 if (!node)
94 return ERR_PTR(-ENOMEM);
95
96 node->qid = MLX5E_QOS_QID_INNER;
97 node->classid = MLX5E_HTB_CLASSID_ROOT;
98 hash_add_rcu(priv->htb.qos_tc2node, &node->hnode, node->classid);
99
100 return node;
101 }
102
mlx5e_sw_node_find(struct mlx5e_priv * priv,u32 classid)103 static struct mlx5e_qos_node *mlx5e_sw_node_find(struct mlx5e_priv *priv, u32 classid)
104 {
105 struct mlx5e_qos_node *node = NULL;
106
107 hash_for_each_possible(priv->htb.qos_tc2node, node, hnode, classid) {
108 if (node->classid == classid)
109 break;
110 }
111
112 return node;
113 }
114
mlx5e_sw_node_find_rcu(struct mlx5e_priv * priv,u32 classid)115 static struct mlx5e_qos_node *mlx5e_sw_node_find_rcu(struct mlx5e_priv *priv, u32 classid)
116 {
117 struct mlx5e_qos_node *node = NULL;
118
119 hash_for_each_possible_rcu(priv->htb.qos_tc2node, node, hnode, classid) {
120 if (node->classid == classid)
121 break;
122 }
123
124 return node;
125 }
126
mlx5e_sw_node_delete(struct mlx5e_priv * priv,struct mlx5e_qos_node * node)127 static void mlx5e_sw_node_delete(struct mlx5e_priv *priv, struct mlx5e_qos_node *node)
128 {
129 hash_del_rcu(&node->hnode);
130 if (node->qid != MLX5E_QOS_QID_INNER) {
131 __clear_bit(node->qid, priv->htb.qos_used_qids);
132 mlx5e_update_tx_netdev_queues(priv);
133 }
134 /* Make sure this qid is no longer selected by mlx5e_select_queue, so
135 * that mlx5e_reactivate_qos_sq can safely restart the netdev TX queue.
136 */
137 synchronize_net();
138 kfree(node);
139 }
140
141 /* TX datapath API */
142
mlx5e_qid_from_qos(struct mlx5e_channels * chs,u16 qid)143 static u16 mlx5e_qid_from_qos(struct mlx5e_channels *chs, u16 qid)
144 {
145 /* These channel params are safe to access from the datapath, because:
146 * 1. This function is called only after checking priv->htb.maj_id != 0,
147 * and the number of queues can't change while HTB offload is active.
148 * 2. When priv->htb.maj_id becomes 0, synchronize_rcu waits for
149 * mlx5e_select_queue to finish while holding priv->state_lock,
150 * preventing other code from changing the number of queues.
151 */
152 bool is_ptp = MLX5E_GET_PFLAG(&chs->params, MLX5E_PFLAG_TX_PORT_TS);
153
154 return (chs->params.num_channels + is_ptp) * mlx5e_get_dcb_num_tc(&chs->params) + qid;
155 }
156
mlx5e_get_txq_by_classid(struct mlx5e_priv * priv,u16 classid)157 int mlx5e_get_txq_by_classid(struct mlx5e_priv *priv, u16 classid)
158 {
159 struct mlx5e_qos_node *node;
160 u16 qid;
161 int res;
162
163 rcu_read_lock();
164
165 node = mlx5e_sw_node_find_rcu(priv, classid);
166 if (!node) {
167 res = -ENOENT;
168 goto out;
169 }
170 qid = READ_ONCE(node->qid);
171 if (qid == MLX5E_QOS_QID_INNER) {
172 res = -EINVAL;
173 goto out;
174 }
175 res = mlx5e_qid_from_qos(&priv->channels, qid);
176
177 out:
178 rcu_read_unlock();
179 return res;
180 }
181
mlx5e_get_qos_sq(struct mlx5e_priv * priv,int qid)182 static struct mlx5e_txqsq *mlx5e_get_qos_sq(struct mlx5e_priv *priv, int qid)
183 {
184 struct mlx5e_params *params = &priv->channels.params;
185 struct mlx5e_txqsq __rcu **qos_sqs;
186 struct mlx5e_channel *c;
187 int ix;
188
189 ix = qid % params->num_channels;
190 qid /= params->num_channels;
191 c = priv->channels.c[ix];
192
193 qos_sqs = mlx5e_state_dereference(priv, c->qos_sqs);
194 return mlx5e_state_dereference(priv, qos_sqs[qid]);
195 }
196
197 /* SQ lifecycle */
198
mlx5e_open_qos_sq(struct mlx5e_priv * priv,struct mlx5e_channels * chs,struct mlx5e_qos_node * node)199 static int mlx5e_open_qos_sq(struct mlx5e_priv *priv, struct mlx5e_channels *chs,
200 struct mlx5e_qos_node *node)
201 {
202 struct mlx5e_create_cq_param ccp = {};
203 struct mlx5e_txqsq __rcu **qos_sqs;
204 struct mlx5e_sq_param param_sq;
205 struct mlx5e_cq_param param_cq;
206 int txq_ix, ix, qid, err = 0;
207 struct mlx5e_params *params;
208 struct mlx5e_channel *c;
209 struct mlx5e_txqsq *sq;
210
211 params = &chs->params;
212
213 txq_ix = mlx5e_qid_from_qos(chs, node->qid);
214
215 WARN_ON(node->qid > priv->htb.max_qos_sqs);
216 if (node->qid == priv->htb.max_qos_sqs) {
217 struct mlx5e_sq_stats *stats, **stats_list = NULL;
218
219 if (priv->htb.max_qos_sqs == 0) {
220 stats_list = kvcalloc(mlx5e_qos_max_leaf_nodes(priv->mdev),
221 sizeof(*stats_list),
222 GFP_KERNEL);
223 if (!stats_list)
224 return -ENOMEM;
225 }
226 stats = kzalloc(sizeof(*stats), GFP_KERNEL);
227 if (!stats) {
228 kvfree(stats_list);
229 return -ENOMEM;
230 }
231 if (stats_list)
232 WRITE_ONCE(priv->htb.qos_sq_stats, stats_list);
233 WRITE_ONCE(priv->htb.qos_sq_stats[node->qid], stats);
234 /* Order max_qos_sqs increment after writing the array pointer.
235 * Pairs with smp_load_acquire in en_stats.c.
236 */
237 smp_store_release(&priv->htb.max_qos_sqs, priv->htb.max_qos_sqs + 1);
238 }
239
240 ix = node->qid % params->num_channels;
241 qid = node->qid / params->num_channels;
242 c = chs->c[ix];
243
244 qos_sqs = mlx5e_state_dereference(priv, c->qos_sqs);
245 sq = kzalloc(sizeof(*sq), GFP_KERNEL);
246
247 if (!sq)
248 return -ENOMEM;
249
250 mlx5e_build_create_cq_param(&ccp, c);
251
252 memset(¶m_sq, 0, sizeof(param_sq));
253 memset(¶m_cq, 0, sizeof(param_cq));
254 mlx5e_build_sq_param(priv->mdev, params, ¶m_sq);
255 mlx5e_build_tx_cq_param(priv->mdev, params, ¶m_cq);
256 err = mlx5e_open_cq(priv, params->tx_cq_moderation, ¶m_cq, &ccp, &sq->cq);
257 if (err)
258 goto err_free_sq;
259 err = mlx5e_open_txqsq(c, priv->tisn[c->lag_port][0], txq_ix, params,
260 ¶m_sq, sq, 0, node->hw_id,
261 priv->htb.qos_sq_stats[node->qid]);
262 if (err)
263 goto err_close_cq;
264
265 rcu_assign_pointer(qos_sqs[qid], sq);
266
267 return 0;
268
269 err_close_cq:
270 mlx5e_close_cq(&sq->cq);
271 err_free_sq:
272 kfree(sq);
273 return err;
274 }
275
mlx5e_activate_qos_sq(struct mlx5e_priv * priv,struct mlx5e_qos_node * node)276 static void mlx5e_activate_qos_sq(struct mlx5e_priv *priv, struct mlx5e_qos_node *node)
277 {
278 struct mlx5e_txqsq *sq;
279 u16 qid;
280
281 sq = mlx5e_get_qos_sq(priv, node->qid);
282
283 qid = mlx5e_qid_from_qos(&priv->channels, node->qid);
284
285 /* If it's a new queue, it will be marked as started at this point.
286 * Stop it before updating txq2sq.
287 */
288 mlx5e_tx_disable_queue(netdev_get_tx_queue(priv->netdev, qid));
289
290 priv->txq2sq[qid] = sq;
291
292 /* Make the change to txq2sq visible before the queue is started.
293 * As mlx5e_xmit runs under a spinlock, there is an implicit ACQUIRE,
294 * which pairs with this barrier.
295 */
296 smp_wmb();
297
298 qos_dbg(priv->mdev, "Activate QoS SQ qid %u\n", node->qid);
299 mlx5e_activate_txqsq(sq);
300 }
301
mlx5e_deactivate_qos_sq(struct mlx5e_priv * priv,u16 qid)302 static void mlx5e_deactivate_qos_sq(struct mlx5e_priv *priv, u16 qid)
303 {
304 struct mlx5e_txqsq *sq;
305
306 sq = mlx5e_get_qos_sq(priv, qid);
307 if (!sq) /* Handle the case when the SQ failed to open. */
308 return;
309
310 qos_dbg(priv->mdev, "Deactivate QoS SQ qid %u\n", qid);
311 mlx5e_deactivate_txqsq(sq);
312
313 priv->txq2sq[mlx5e_qid_from_qos(&priv->channels, qid)] = NULL;
314
315 /* Make the change to txq2sq visible before the queue is started again.
316 * As mlx5e_xmit runs under a spinlock, there is an implicit ACQUIRE,
317 * which pairs with this barrier.
318 */
319 smp_wmb();
320 }
321
mlx5e_close_qos_sq(struct mlx5e_priv * priv,u16 qid)322 static void mlx5e_close_qos_sq(struct mlx5e_priv *priv, u16 qid)
323 {
324 struct mlx5e_txqsq __rcu **qos_sqs;
325 struct mlx5e_params *params;
326 struct mlx5e_channel *c;
327 struct mlx5e_txqsq *sq;
328 int ix;
329
330 params = &priv->channels.params;
331
332 ix = qid % params->num_channels;
333 qid /= params->num_channels;
334 c = priv->channels.c[ix];
335 qos_sqs = mlx5e_state_dereference(priv, c->qos_sqs);
336 sq = rcu_replace_pointer(qos_sqs[qid], NULL, lockdep_is_held(&priv->state_lock));
337 if (!sq) /* Handle the case when the SQ failed to open. */
338 return;
339
340 synchronize_rcu(); /* Sync with NAPI. */
341
342 mlx5e_close_txqsq(sq);
343 mlx5e_close_cq(&sq->cq);
344 kfree(sq);
345 }
346
mlx5e_qos_close_queues(struct mlx5e_channel * c)347 void mlx5e_qos_close_queues(struct mlx5e_channel *c)
348 {
349 struct mlx5e_txqsq __rcu **qos_sqs;
350 int i;
351
352 qos_sqs = rcu_replace_pointer(c->qos_sqs, NULL, lockdep_is_held(&c->priv->state_lock));
353 if (!qos_sqs)
354 return;
355 synchronize_rcu(); /* Sync with NAPI. */
356
357 for (i = 0; i < c->qos_sqs_size; i++) {
358 struct mlx5e_txqsq *sq;
359
360 sq = mlx5e_state_dereference(c->priv, qos_sqs[i]);
361 if (!sq) /* Handle the case when the SQ failed to open. */
362 continue;
363
364 mlx5e_close_txqsq(sq);
365 mlx5e_close_cq(&sq->cq);
366 kfree(sq);
367 }
368
369 kvfree(qos_sqs);
370 }
371
mlx5e_qos_close_all_queues(struct mlx5e_channels * chs)372 static void mlx5e_qos_close_all_queues(struct mlx5e_channels *chs)
373 {
374 int i;
375
376 for (i = 0; i < chs->num; i++)
377 mlx5e_qos_close_queues(chs->c[i]);
378 }
379
mlx5e_qos_alloc_queues(struct mlx5e_priv * priv,struct mlx5e_channels * chs)380 static int mlx5e_qos_alloc_queues(struct mlx5e_priv *priv, struct mlx5e_channels *chs)
381 {
382 u16 qos_sqs_size;
383 int i;
384
385 qos_sqs_size = DIV_ROUND_UP(mlx5e_qos_max_leaf_nodes(priv->mdev), chs->num);
386
387 for (i = 0; i < chs->num; i++) {
388 struct mlx5e_txqsq **sqs;
389
390 sqs = kvcalloc(qos_sqs_size, sizeof(struct mlx5e_txqsq *), GFP_KERNEL);
391 if (!sqs)
392 goto err_free;
393
394 WRITE_ONCE(chs->c[i]->qos_sqs_size, qos_sqs_size);
395 smp_wmb(); /* Pairs with mlx5e_napi_poll. */
396 rcu_assign_pointer(chs->c[i]->qos_sqs, sqs);
397 }
398
399 return 0;
400
401 err_free:
402 while (--i >= 0) {
403 struct mlx5e_txqsq **sqs;
404
405 sqs = rcu_replace_pointer(chs->c[i]->qos_sqs, NULL,
406 lockdep_is_held(&priv->state_lock));
407
408 synchronize_rcu(); /* Sync with NAPI. */
409 kvfree(sqs);
410 }
411 return -ENOMEM;
412 }
413
mlx5e_qos_open_queues(struct mlx5e_priv * priv,struct mlx5e_channels * chs)414 int mlx5e_qos_open_queues(struct mlx5e_priv *priv, struct mlx5e_channels *chs)
415 {
416 struct mlx5e_qos_node *node = NULL;
417 int bkt, err;
418
419 if (!priv->htb.maj_id)
420 return 0;
421
422 err = mlx5e_qos_alloc_queues(priv, chs);
423 if (err)
424 return err;
425
426 hash_for_each(priv->htb.qos_tc2node, bkt, node, hnode) {
427 if (node->qid == MLX5E_QOS_QID_INNER)
428 continue;
429 err = mlx5e_open_qos_sq(priv, chs, node);
430 if (err) {
431 mlx5e_qos_close_all_queues(chs);
432 return err;
433 }
434 }
435
436 return 0;
437 }
438
mlx5e_qos_activate_queues(struct mlx5e_priv * priv)439 void mlx5e_qos_activate_queues(struct mlx5e_priv *priv)
440 {
441 struct mlx5e_qos_node *node = NULL;
442 int bkt;
443
444 hash_for_each(priv->htb.qos_tc2node, bkt, node, hnode) {
445 if (node->qid == MLX5E_QOS_QID_INNER)
446 continue;
447 mlx5e_activate_qos_sq(priv, node);
448 }
449 }
450
mlx5e_qos_deactivate_queues(struct mlx5e_channel * c)451 void mlx5e_qos_deactivate_queues(struct mlx5e_channel *c)
452 {
453 struct mlx5e_params *params = &c->priv->channels.params;
454 struct mlx5e_txqsq __rcu **qos_sqs;
455 int i;
456
457 qos_sqs = mlx5e_state_dereference(c->priv, c->qos_sqs);
458 if (!qos_sqs)
459 return;
460
461 for (i = 0; i < c->qos_sqs_size; i++) {
462 u16 qid = params->num_channels * i + c->ix;
463 struct mlx5e_txqsq *sq;
464
465 sq = mlx5e_state_dereference(c->priv, qos_sqs[i]);
466 if (!sq) /* Handle the case when the SQ failed to open. */
467 continue;
468
469 qos_dbg(c->mdev, "Deactivate QoS SQ qid %u\n", qid);
470 mlx5e_deactivate_txqsq(sq);
471
472 /* The queue is disabled, no synchronization with datapath is needed. */
473 c->priv->txq2sq[mlx5e_qid_from_qos(&c->priv->channels, qid)] = NULL;
474 }
475 }
476
mlx5e_qos_deactivate_all_queues(struct mlx5e_channels * chs)477 static void mlx5e_qos_deactivate_all_queues(struct mlx5e_channels *chs)
478 {
479 int i;
480
481 for (i = 0; i < chs->num; i++)
482 mlx5e_qos_deactivate_queues(chs->c[i]);
483 }
484
485 /* HTB API */
486
mlx5e_htb_root_add(struct mlx5e_priv * priv,u16 htb_maj_id,u16 htb_defcls,struct netlink_ext_ack * extack)487 int mlx5e_htb_root_add(struct mlx5e_priv *priv, u16 htb_maj_id, u16 htb_defcls,
488 struct netlink_ext_ack *extack)
489 {
490 struct mlx5e_qos_node *root;
491 bool opened;
492 int err;
493
494 qos_dbg(priv->mdev, "TC_HTB_CREATE handle %04x:, default :%04x\n", htb_maj_id, htb_defcls);
495
496 if (!mlx5_qos_is_supported(priv->mdev)) {
497 NL_SET_ERR_MSG_MOD(extack,
498 "Missing QoS capabilities. Try disabling SRIOV or use a supported device.");
499 return -EOPNOTSUPP;
500 }
501
502 opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
503 if (opened) {
504 mlx5e_selq_prepare(&priv->selq, &priv->channels.params, true);
505
506 err = mlx5e_qos_alloc_queues(priv, &priv->channels);
507 if (err)
508 goto err_cancel_selq;
509 }
510
511 root = mlx5e_sw_node_create_root(priv);
512 if (IS_ERR(root)) {
513 err = PTR_ERR(root);
514 goto err_free_queues;
515 }
516
517 err = mlx5_qos_create_root_node(priv->mdev, &root->hw_id);
518 if (err) {
519 NL_SET_ERR_MSG_MOD(extack, "Firmware error. Try upgrading firmware.");
520 goto err_sw_node_delete;
521 }
522
523 WRITE_ONCE(priv->htb.defcls, htb_defcls);
524 /* Order maj_id after defcls - pairs with
525 * mlx5e_select_queue/mlx5e_select_htb_queues.
526 */
527 smp_store_release(&priv->htb.maj_id, htb_maj_id);
528
529 if (opened)
530 mlx5e_selq_apply(&priv->selq);
531
532 return 0;
533
534 err_sw_node_delete:
535 mlx5e_sw_node_delete(priv, root);
536
537 err_free_queues:
538 if (opened)
539 mlx5e_qos_close_all_queues(&priv->channels);
540 err_cancel_selq:
541 mlx5e_selq_cancel(&priv->selq);
542 return err;
543 }
544
mlx5e_htb_root_del(struct mlx5e_priv * priv)545 int mlx5e_htb_root_del(struct mlx5e_priv *priv)
546 {
547 struct mlx5e_qos_node *root;
548 int err;
549
550 qos_dbg(priv->mdev, "TC_HTB_DESTROY\n");
551
552 /* Wait until real_num_tx_queues is updated for mlx5e_select_queue,
553 * so that we can safely switch to its non-HTB non-PTP fastpath.
554 */
555 synchronize_net();
556
557 mlx5e_selq_prepare(&priv->selq, &priv->channels.params, false);
558 mlx5e_selq_apply(&priv->selq);
559
560 WRITE_ONCE(priv->htb.maj_id, 0);
561
562 root = mlx5e_sw_node_find(priv, MLX5E_HTB_CLASSID_ROOT);
563 if (!root) {
564 qos_err(priv->mdev, "Failed to find the root node in the QoS tree\n");
565 return -ENOENT;
566 }
567 err = mlx5_qos_destroy_node(priv->mdev, root->hw_id);
568 if (err)
569 qos_err(priv->mdev, "Failed to destroy root node %u, err = %d\n",
570 root->hw_id, err);
571 mlx5e_sw_node_delete(priv, root);
572
573 mlx5e_qos_deactivate_all_queues(&priv->channels);
574 mlx5e_qos_close_all_queues(&priv->channels);
575
576 return err;
577 }
578
mlx5e_htb_convert_rate(struct mlx5e_priv * priv,u64 rate,struct mlx5e_qos_node * parent,u32 * bw_share)579 static int mlx5e_htb_convert_rate(struct mlx5e_priv *priv, u64 rate,
580 struct mlx5e_qos_node *parent, u32 *bw_share)
581 {
582 u64 share = 0;
583
584 while (parent->classid != MLX5E_HTB_CLASSID_ROOT && !parent->max_average_bw)
585 parent = parent->parent;
586
587 if (parent->max_average_bw)
588 share = div64_u64(div_u64(rate * 100, BYTES_IN_MBIT),
589 parent->max_average_bw);
590 else
591 share = 101;
592
593 *bw_share = share == 0 ? 1 : share > 100 ? 0 : share;
594
595 qos_dbg(priv->mdev, "Convert: rate %llu, parent ceil %llu -> bw_share %u\n",
596 rate, (u64)parent->max_average_bw * BYTES_IN_MBIT, *bw_share);
597
598 return 0;
599 }
600
mlx5e_htb_convert_ceil(struct mlx5e_priv * priv,u64 ceil,u32 * max_average_bw)601 static void mlx5e_htb_convert_ceil(struct mlx5e_priv *priv, u64 ceil, u32 *max_average_bw)
602 {
603 /* Hardware treats 0 as "unlimited", set at least 1. */
604 *max_average_bw = max_t(u32, div_u64(ceil, BYTES_IN_MBIT), 1);
605
606 qos_dbg(priv->mdev, "Convert: ceil %llu -> max_average_bw %u\n",
607 ceil, *max_average_bw);
608 }
609
mlx5e_htb_leaf_alloc_queue(struct mlx5e_priv * priv,u16 classid,u32 parent_classid,u64 rate,u64 ceil,struct netlink_ext_ack * extack)610 int mlx5e_htb_leaf_alloc_queue(struct mlx5e_priv *priv, u16 classid,
611 u32 parent_classid, u64 rate, u64 ceil,
612 struct netlink_ext_ack *extack)
613 {
614 struct mlx5e_qos_node *node, *parent;
615 int qid;
616 int err;
617
618 qos_dbg(priv->mdev, "TC_HTB_LEAF_ALLOC_QUEUE classid %04x, parent %04x, rate %llu, ceil %llu\n",
619 classid, parent_classid, rate, ceil);
620
621 qid = mlx5e_find_unused_qos_qid(priv);
622 if (qid < 0) {
623 NL_SET_ERR_MSG_MOD(extack, "Maximum amount of leaf classes is reached.");
624 return qid;
625 }
626
627 parent = mlx5e_sw_node_find(priv, parent_classid);
628 if (!parent)
629 return -EINVAL;
630
631 node = mlx5e_sw_node_create_leaf(priv, classid, qid, parent);
632 if (IS_ERR(node))
633 return PTR_ERR(node);
634
635 node->rate = rate;
636 mlx5e_htb_convert_rate(priv, rate, node->parent, &node->bw_share);
637 mlx5e_htb_convert_ceil(priv, ceil, &node->max_average_bw);
638
639 err = mlx5_qos_create_leaf_node(priv->mdev, node->parent->hw_id,
640 node->bw_share, node->max_average_bw,
641 &node->hw_id);
642 if (err) {
643 NL_SET_ERR_MSG_MOD(extack, "Firmware error when creating a leaf node.");
644 qos_err(priv->mdev, "Failed to create a leaf node (class %04x), err = %d\n",
645 classid, err);
646 mlx5e_sw_node_delete(priv, node);
647 return err;
648 }
649
650 if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
651 err = mlx5e_open_qos_sq(priv, &priv->channels, node);
652 if (err) {
653 NL_SET_ERR_MSG_MOD(extack, "Error creating an SQ.");
654 qos_warn(priv->mdev, "Failed to create a QoS SQ (class %04x), err = %d\n",
655 classid, err);
656 } else {
657 mlx5e_activate_qos_sq(priv, node);
658 }
659 }
660
661 return mlx5e_qid_from_qos(&priv->channels, node->qid);
662 }
663
mlx5e_htb_leaf_to_inner(struct mlx5e_priv * priv,u16 classid,u16 child_classid,u64 rate,u64 ceil,struct netlink_ext_ack * extack)664 int mlx5e_htb_leaf_to_inner(struct mlx5e_priv *priv, u16 classid, u16 child_classid,
665 u64 rate, u64 ceil, struct netlink_ext_ack *extack)
666 {
667 struct mlx5e_qos_node *node, *child;
668 int err, tmp_err;
669 u32 new_hw_id;
670 u16 qid;
671
672 qos_dbg(priv->mdev, "TC_HTB_LEAF_TO_INNER classid %04x, upcoming child %04x, rate %llu, ceil %llu\n",
673 classid, child_classid, rate, ceil);
674
675 node = mlx5e_sw_node_find(priv, classid);
676 if (!node)
677 return -ENOENT;
678
679 err = mlx5_qos_create_inner_node(priv->mdev, node->parent->hw_id,
680 node->bw_share, node->max_average_bw,
681 &new_hw_id);
682 if (err) {
683 NL_SET_ERR_MSG_MOD(extack, "Firmware error when creating an inner node.");
684 qos_err(priv->mdev, "Failed to create an inner node (class %04x), err = %d\n",
685 classid, err);
686 return err;
687 }
688
689 /* Intentionally reuse the qid for the upcoming first child. */
690 child = mlx5e_sw_node_create_leaf(priv, child_classid, node->qid, node);
691 if (IS_ERR(child)) {
692 err = PTR_ERR(child);
693 goto err_destroy_hw_node;
694 }
695
696 child->rate = rate;
697 mlx5e_htb_convert_rate(priv, rate, node, &child->bw_share);
698 mlx5e_htb_convert_ceil(priv, ceil, &child->max_average_bw);
699
700 err = mlx5_qos_create_leaf_node(priv->mdev, new_hw_id, child->bw_share,
701 child->max_average_bw, &child->hw_id);
702 if (err) {
703 NL_SET_ERR_MSG_MOD(extack, "Firmware error when creating a leaf node.");
704 qos_err(priv->mdev, "Failed to create a leaf node (class %04x), err = %d\n",
705 classid, err);
706 goto err_delete_sw_node;
707 }
708
709 /* No fail point. */
710
711 qid = node->qid;
712 /* Pairs with mlx5e_get_txq_by_classid. */
713 WRITE_ONCE(node->qid, MLX5E_QOS_QID_INNER);
714
715 if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
716 mlx5e_deactivate_qos_sq(priv, qid);
717 mlx5e_close_qos_sq(priv, qid);
718 }
719
720 err = mlx5_qos_destroy_node(priv->mdev, node->hw_id);
721 if (err) /* Not fatal. */
722 qos_warn(priv->mdev, "Failed to destroy leaf node %u (class %04x), err = %d\n",
723 node->hw_id, classid, err);
724
725 node->hw_id = new_hw_id;
726
727 if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
728 err = mlx5e_open_qos_sq(priv, &priv->channels, child);
729 if (err) {
730 NL_SET_ERR_MSG_MOD(extack, "Error creating an SQ.");
731 qos_warn(priv->mdev, "Failed to create a QoS SQ (class %04x), err = %d\n",
732 classid, err);
733 } else {
734 mlx5e_activate_qos_sq(priv, child);
735 }
736 }
737
738 return 0;
739
740 err_delete_sw_node:
741 child->qid = MLX5E_QOS_QID_INNER;
742 mlx5e_sw_node_delete(priv, child);
743
744 err_destroy_hw_node:
745 tmp_err = mlx5_qos_destroy_node(priv->mdev, new_hw_id);
746 if (tmp_err) /* Not fatal. */
747 qos_warn(priv->mdev, "Failed to roll back creation of an inner node %u (class %04x), err = %d\n",
748 new_hw_id, classid, tmp_err);
749 return err;
750 }
751
mlx5e_sw_node_find_by_qid(struct mlx5e_priv * priv,u16 qid)752 static struct mlx5e_qos_node *mlx5e_sw_node_find_by_qid(struct mlx5e_priv *priv, u16 qid)
753 {
754 struct mlx5e_qos_node *node = NULL;
755 int bkt;
756
757 hash_for_each(priv->htb.qos_tc2node, bkt, node, hnode)
758 if (node->qid == qid)
759 break;
760
761 return node;
762 }
763
mlx5e_reactivate_qos_sq(struct mlx5e_priv * priv,u16 qid,struct netdev_queue * txq)764 static void mlx5e_reactivate_qos_sq(struct mlx5e_priv *priv, u16 qid, struct netdev_queue *txq)
765 {
766 qos_dbg(priv->mdev, "Reactivate QoS SQ qid %u\n", qid);
767 netdev_tx_reset_queue(txq);
768 netif_tx_start_queue(txq);
769 }
770
mlx5e_reset_qdisc(struct net_device * dev,u16 qid)771 static void mlx5e_reset_qdisc(struct net_device *dev, u16 qid)
772 {
773 struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, qid);
774 struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
775
776 if (!qdisc)
777 return;
778
779 spin_lock_bh(qdisc_lock(qdisc));
780 qdisc_reset(qdisc);
781 spin_unlock_bh(qdisc_lock(qdisc));
782 }
783
mlx5e_htb_leaf_del(struct mlx5e_priv * priv,u16 * classid,struct netlink_ext_ack * extack)784 int mlx5e_htb_leaf_del(struct mlx5e_priv *priv, u16 *classid,
785 struct netlink_ext_ack *extack)
786 {
787 struct mlx5e_qos_node *node;
788 struct netdev_queue *txq;
789 u16 qid, moved_qid;
790 bool opened;
791 int err;
792
793 qos_dbg(priv->mdev, "TC_HTB_LEAF_DEL classid %04x\n", *classid);
794
795 node = mlx5e_sw_node_find(priv, *classid);
796 if (!node)
797 return -ENOENT;
798
799 /* Store qid for reuse. */
800 qid = node->qid;
801
802 opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
803 if (opened) {
804 txq = netdev_get_tx_queue(priv->netdev,
805 mlx5e_qid_from_qos(&priv->channels, qid));
806 mlx5e_deactivate_qos_sq(priv, qid);
807 mlx5e_close_qos_sq(priv, qid);
808 }
809
810 err = mlx5_qos_destroy_node(priv->mdev, node->hw_id);
811 if (err) /* Not fatal. */
812 qos_warn(priv->mdev, "Failed to destroy leaf node %u (class %04x), err = %d\n",
813 node->hw_id, *classid, err);
814
815 mlx5e_sw_node_delete(priv, node);
816
817 moved_qid = mlx5e_qos_cur_leaf_nodes(priv);
818
819 if (moved_qid == 0) {
820 /* The last QoS SQ was just destroyed. */
821 if (opened)
822 mlx5e_reactivate_qos_sq(priv, qid, txq);
823 return 0;
824 }
825 moved_qid--;
826
827 if (moved_qid < qid) {
828 /* The highest QoS SQ was just destroyed. */
829 WARN(moved_qid != qid - 1, "Gaps in queue numeration: destroyed queue %u, the highest queue is %u",
830 qid, moved_qid);
831 if (opened)
832 mlx5e_reactivate_qos_sq(priv, qid, txq);
833 return 0;
834 }
835
836 WARN(moved_qid == qid, "Can't move node with qid %u to itself", qid);
837 qos_dbg(priv->mdev, "Moving QoS SQ %u to %u\n", moved_qid, qid);
838
839 node = mlx5e_sw_node_find_by_qid(priv, moved_qid);
840 WARN(!node, "Could not find a node with qid %u to move to queue %u",
841 moved_qid, qid);
842
843 /* Stop traffic to the old queue. */
844 WRITE_ONCE(node->qid, MLX5E_QOS_QID_INNER);
845 __clear_bit(moved_qid, priv->htb.qos_used_qids);
846
847 if (opened) {
848 txq = netdev_get_tx_queue(priv->netdev,
849 mlx5e_qid_from_qos(&priv->channels, moved_qid));
850 mlx5e_deactivate_qos_sq(priv, moved_qid);
851 mlx5e_close_qos_sq(priv, moved_qid);
852 }
853
854 /* Prevent packets from the old class from getting into the new one. */
855 mlx5e_reset_qdisc(priv->netdev, moved_qid);
856
857 __set_bit(qid, priv->htb.qos_used_qids);
858 WRITE_ONCE(node->qid, qid);
859
860 if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
861 err = mlx5e_open_qos_sq(priv, &priv->channels, node);
862 if (err) {
863 NL_SET_ERR_MSG_MOD(extack, "Error creating an SQ.");
864 qos_warn(priv->mdev, "Failed to create a QoS SQ (class %04x) while moving qid %u to %u, err = %d\n",
865 node->classid, moved_qid, qid, err);
866 } else {
867 mlx5e_activate_qos_sq(priv, node);
868 }
869 }
870
871 mlx5e_update_tx_netdev_queues(priv);
872 if (opened)
873 mlx5e_reactivate_qos_sq(priv, moved_qid, txq);
874
875 *classid = node->classid;
876 return 0;
877 }
878
mlx5e_htb_leaf_del_last(struct mlx5e_priv * priv,u16 classid,bool force,struct netlink_ext_ack * extack)879 int mlx5e_htb_leaf_del_last(struct mlx5e_priv *priv, u16 classid, bool force,
880 struct netlink_ext_ack *extack)
881 {
882 struct mlx5e_qos_node *node, *parent;
883 u32 old_hw_id, new_hw_id;
884 int err, saved_err = 0;
885 u16 qid;
886
887 qos_dbg(priv->mdev, "TC_HTB_LEAF_DEL_LAST%s classid %04x\n",
888 force ? "_FORCE" : "", classid);
889
890 node = mlx5e_sw_node_find(priv, classid);
891 if (!node)
892 return -ENOENT;
893
894 err = mlx5_qos_create_leaf_node(priv->mdev, node->parent->parent->hw_id,
895 node->parent->bw_share,
896 node->parent->max_average_bw,
897 &new_hw_id);
898 if (err) {
899 NL_SET_ERR_MSG_MOD(extack, "Firmware error when creating a leaf node.");
900 qos_err(priv->mdev, "Failed to create a leaf node (class %04x), err = %d\n",
901 classid, err);
902 if (!force)
903 return err;
904 saved_err = err;
905 }
906
907 /* Store qid for reuse and prevent clearing the bit. */
908 qid = node->qid;
909 /* Pairs with mlx5e_get_txq_by_classid. */
910 WRITE_ONCE(node->qid, MLX5E_QOS_QID_INNER);
911
912 if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
913 mlx5e_deactivate_qos_sq(priv, qid);
914 mlx5e_close_qos_sq(priv, qid);
915 }
916
917 /* Prevent packets from the old class from getting into the new one. */
918 mlx5e_reset_qdisc(priv->netdev, qid);
919
920 err = mlx5_qos_destroy_node(priv->mdev, node->hw_id);
921 if (err) /* Not fatal. */
922 qos_warn(priv->mdev, "Failed to destroy leaf node %u (class %04x), err = %d\n",
923 node->hw_id, classid, err);
924
925 parent = node->parent;
926 mlx5e_sw_node_delete(priv, node);
927
928 node = parent;
929 WRITE_ONCE(node->qid, qid);
930
931 /* Early return on error in force mode. Parent will still be an inner
932 * node to be deleted by a following delete operation.
933 */
934 if (saved_err)
935 return saved_err;
936
937 old_hw_id = node->hw_id;
938 node->hw_id = new_hw_id;
939
940 if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
941 err = mlx5e_open_qos_sq(priv, &priv->channels, node);
942 if (err) {
943 NL_SET_ERR_MSG_MOD(extack, "Error creating an SQ.");
944 qos_warn(priv->mdev, "Failed to create a QoS SQ (class %04x), err = %d\n",
945 classid, err);
946 } else {
947 mlx5e_activate_qos_sq(priv, node);
948 }
949 }
950
951 err = mlx5_qos_destroy_node(priv->mdev, old_hw_id);
952 if (err) /* Not fatal. */
953 qos_warn(priv->mdev, "Failed to destroy leaf node %u (class %04x), err = %d\n",
954 node->hw_id, classid, err);
955
956 return 0;
957 }
958
mlx5e_qos_update_children(struct mlx5e_priv * priv,struct mlx5e_qos_node * node,struct netlink_ext_ack * extack)959 static int mlx5e_qos_update_children(struct mlx5e_priv *priv, struct mlx5e_qos_node *node,
960 struct netlink_ext_ack *extack)
961 {
962 struct mlx5e_qos_node *child;
963 int err = 0;
964 int bkt;
965
966 hash_for_each(priv->htb.qos_tc2node, bkt, child, hnode) {
967 u32 old_bw_share = child->bw_share;
968 int err_one;
969
970 if (child->parent != node)
971 continue;
972
973 mlx5e_htb_convert_rate(priv, child->rate, node, &child->bw_share);
974 if (child->bw_share == old_bw_share)
975 continue;
976
977 err_one = mlx5_qos_update_node(priv->mdev, child->hw_id, child->bw_share,
978 child->max_average_bw, child->hw_id);
979 if (!err && err_one) {
980 err = err_one;
981
982 NL_SET_ERR_MSG_MOD(extack, "Firmware error when modifying a child node.");
983 qos_err(priv->mdev, "Failed to modify a child node (class %04x), err = %d\n",
984 node->classid, err);
985 }
986 }
987
988 return err;
989 }
990
mlx5e_htb_node_modify(struct mlx5e_priv * priv,u16 classid,u64 rate,u64 ceil,struct netlink_ext_ack * extack)991 int mlx5e_htb_node_modify(struct mlx5e_priv *priv, u16 classid, u64 rate, u64 ceil,
992 struct netlink_ext_ack *extack)
993 {
994 u32 bw_share, max_average_bw;
995 struct mlx5e_qos_node *node;
996 bool ceil_changed = false;
997 int err;
998
999 qos_dbg(priv->mdev, "TC_HTB_LEAF_MODIFY classid %04x, rate %llu, ceil %llu\n",
1000 classid, rate, ceil);
1001
1002 node = mlx5e_sw_node_find(priv, classid);
1003 if (!node)
1004 return -ENOENT;
1005
1006 node->rate = rate;
1007 mlx5e_htb_convert_rate(priv, rate, node->parent, &bw_share);
1008 mlx5e_htb_convert_ceil(priv, ceil, &max_average_bw);
1009
1010 err = mlx5_qos_update_node(priv->mdev, node->parent->hw_id, bw_share,
1011 max_average_bw, node->hw_id);
1012 if (err) {
1013 NL_SET_ERR_MSG_MOD(extack, "Firmware error when modifying a node.");
1014 qos_err(priv->mdev, "Failed to modify a node (class %04x), err = %d\n",
1015 classid, err);
1016 return err;
1017 }
1018
1019 if (max_average_bw != node->max_average_bw)
1020 ceil_changed = true;
1021
1022 node->bw_share = bw_share;
1023 node->max_average_bw = max_average_bw;
1024
1025 if (ceil_changed)
1026 err = mlx5e_qos_update_children(priv, node, extack);
1027
1028 return err;
1029 }
1030
1031 struct mlx5e_mqprio_rl {
1032 struct mlx5_core_dev *mdev;
1033 u32 root_id;
1034 u32 *leaves_id;
1035 u8 num_tc;
1036 };
1037
mlx5e_mqprio_rl_alloc(void)1038 struct mlx5e_mqprio_rl *mlx5e_mqprio_rl_alloc(void)
1039 {
1040 return kvzalloc(sizeof(struct mlx5e_mqprio_rl), GFP_KERNEL);
1041 }
1042
mlx5e_mqprio_rl_free(struct mlx5e_mqprio_rl * rl)1043 void mlx5e_mqprio_rl_free(struct mlx5e_mqprio_rl *rl)
1044 {
1045 kvfree(rl);
1046 }
1047
mlx5e_mqprio_rl_init(struct mlx5e_mqprio_rl * rl,struct mlx5_core_dev * mdev,u8 num_tc,u64 max_rate[])1048 int mlx5e_mqprio_rl_init(struct mlx5e_mqprio_rl *rl, struct mlx5_core_dev *mdev, u8 num_tc,
1049 u64 max_rate[])
1050 {
1051 int err;
1052 int tc;
1053
1054 if (!mlx5_qos_is_supported(mdev)) {
1055 qos_warn(mdev, "Missing QoS capabilities. Try disabling SRIOV or use a supported device.");
1056 return -EOPNOTSUPP;
1057 }
1058 if (num_tc > mlx5e_qos_max_leaf_nodes(mdev))
1059 return -EINVAL;
1060
1061 rl->mdev = mdev;
1062 rl->num_tc = num_tc;
1063 rl->leaves_id = kvcalloc(num_tc, sizeof(*rl->leaves_id), GFP_KERNEL);
1064 if (!rl->leaves_id)
1065 return -ENOMEM;
1066
1067 err = mlx5_qos_create_root_node(mdev, &rl->root_id);
1068 if (err)
1069 goto err_free_leaves;
1070
1071 qos_dbg(mdev, "Root created, id %#x\n", rl->root_id);
1072
1073 for (tc = 0; tc < num_tc; tc++) {
1074 u32 max_average_bw;
1075
1076 max_average_bw = mlx5e_qos_bytes2mbits(mdev, max_rate[tc]);
1077 err = mlx5_qos_create_leaf_node(mdev, rl->root_id, 0, max_average_bw,
1078 &rl->leaves_id[tc]);
1079 if (err)
1080 goto err_destroy_leaves;
1081
1082 qos_dbg(mdev, "Leaf[%d] created, id %#x, max average bw %u Mbits/sec\n",
1083 tc, rl->leaves_id[tc], max_average_bw);
1084 }
1085 return 0;
1086
1087 err_destroy_leaves:
1088 while (--tc >= 0)
1089 mlx5_qos_destroy_node(mdev, rl->leaves_id[tc]);
1090 mlx5_qos_destroy_node(mdev, rl->root_id);
1091 err_free_leaves:
1092 kvfree(rl->leaves_id);
1093 return err;
1094 }
1095
mlx5e_mqprio_rl_cleanup(struct mlx5e_mqprio_rl * rl)1096 void mlx5e_mqprio_rl_cleanup(struct mlx5e_mqprio_rl *rl)
1097 {
1098 int tc;
1099
1100 for (tc = 0; tc < rl->num_tc; tc++)
1101 mlx5_qos_destroy_node(rl->mdev, rl->leaves_id[tc]);
1102 mlx5_qos_destroy_node(rl->mdev, rl->root_id);
1103 kvfree(rl->leaves_id);
1104 }
1105
mlx5e_mqprio_rl_get_node_hw_id(struct mlx5e_mqprio_rl * rl,int tc,u32 * hw_id)1106 int mlx5e_mqprio_rl_get_node_hw_id(struct mlx5e_mqprio_rl *rl, int tc, u32 *hw_id)
1107 {
1108 if (tc >= rl->num_tc)
1109 return -EINVAL;
1110
1111 *hw_id = rl->leaves_id[tc];
1112 return 0;
1113 }
1114