50ea58a3cc948e55cdc24825d1e62dc0704a6e02
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / en / selq.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3
4 #include "selq.h"
5 #include <linux/slab.h>
6 #include <linux/netdevice.h>
7 #include "en.h"
8
9 struct mlx5e_selq_params {
10         unsigned int num_regular_queues;
11         unsigned int num_channels;
12         unsigned int num_tcs;
13         bool is_htb;
14         bool is_ptp;
15 };
16
17 int mlx5e_selq_init(struct mlx5e_selq *selq, struct mutex *state_lock)
18 {
19         struct mlx5e_selq_params *init_params;
20
21         selq->state_lock = state_lock;
22
23         selq->standby = kvzalloc(sizeof(*selq->standby), GFP_KERNEL);
24         if (!selq->standby)
25                 return -ENOMEM;
26
27         init_params = kvzalloc(sizeof(*selq->active), GFP_KERNEL);
28         if (!init_params) {
29                 kvfree(selq->standby);
30                 selq->standby = NULL;
31                 return -ENOMEM;
32         }
33         /* Assign dummy values, so that mlx5e_select_queue won't crash. */
34         *init_params = (struct mlx5e_selq_params) {
35                 .num_regular_queues = 1,
36                 .num_channels = 1,
37                 .num_tcs = 1,
38                 .is_htb = false,
39                 .is_ptp = false,
40         };
41         rcu_assign_pointer(selq->active, init_params);
42
43         return 0;
44 }
45
46 void mlx5e_selq_cleanup(struct mlx5e_selq *selq)
47 {
48         WARN_ON_ONCE(selq->is_prepared);
49
50         kvfree(selq->standby);
51         selq->standby = NULL;
52         selq->is_prepared = true;
53
54         mlx5e_selq_apply(selq);
55
56         kvfree(selq->standby);
57         selq->standby = NULL;
58 }
59
60 void mlx5e_selq_prepare(struct mlx5e_selq *selq, struct mlx5e_params *params, bool htb)
61 {
62         lockdep_assert_held(selq->state_lock);
63         WARN_ON_ONCE(selq->is_prepared);
64
65         selq->is_prepared = true;
66
67         selq->standby->num_channels = params->num_channels;
68         selq->standby->num_tcs = mlx5e_get_dcb_num_tc(params);
69         selq->standby->num_regular_queues =
70                 selq->standby->num_channels * selq->standby->num_tcs;
71         selq->standby->is_htb = htb;
72         selq->standby->is_ptp = MLX5E_GET_PFLAG(params, MLX5E_PFLAG_TX_PORT_TS);
73 }
74
75 void mlx5e_selq_apply(struct mlx5e_selq *selq)
76 {
77         struct mlx5e_selq_params *old_params;
78
79         WARN_ON_ONCE(!selq->is_prepared);
80
81         selq->is_prepared = false;
82
83         old_params = rcu_replace_pointer(selq->active, selq->standby,
84                                          lockdep_is_held(selq->state_lock));
85         synchronize_net(); /* Wait until ndo_select_queue starts emitting correct values. */
86         selq->standby = old_params;
87 }
88
89 void mlx5e_selq_cancel(struct mlx5e_selq *selq)
90 {
91         lockdep_assert_held(selq->state_lock);
92         WARN_ON_ONCE(!selq->is_prepared);
93
94         selq->is_prepared = false;
95 }