xref: /freebsd/sys/dev/mlx5/mlx5_ib/mlx5_ib_cong.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1118063fbSHans Petter Selasky /*-
29b6e45d4SHans Petter Selasky  * Copyright (c) 2013-2020, Mellanox Technologies, Ltd.  All rights reserved.
3118063fbSHans Petter Selasky  *
4118063fbSHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
5118063fbSHans Petter Selasky  * modification, are permitted provided that the following conditions
6118063fbSHans Petter Selasky  * are met:
7118063fbSHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
8118063fbSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
9118063fbSHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
10118063fbSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
11118063fbSHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
12118063fbSHans Petter Selasky  *
13118063fbSHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14118063fbSHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15118063fbSHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16118063fbSHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17118063fbSHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18118063fbSHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19118063fbSHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20118063fbSHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21118063fbSHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22118063fbSHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23118063fbSHans Petter Selasky  * SUCH DAMAGE.
24118063fbSHans Petter Selasky  */
25118063fbSHans Petter Selasky 
2670600979SKonstantin Belousov #include "opt_rss.h"
2770600979SKonstantin Belousov #include "opt_ratelimit.h"
2870600979SKonstantin Belousov 
29*028130b8SKonstantin Belousov #include <dev/mlx5/mlx5_ib/mlx5_ib.h>
30118063fbSHans Petter Selasky #include <dev/mlx5/cmd.h>
31118063fbSHans Petter Selasky 
32118063fbSHans Petter Selasky static const char *mlx5_ib_cong_params_desc[] = {
33118063fbSHans Petter Selasky 	MLX5_IB_CONG_PARAMS(MLX5_IB_STATS_DESC)
34118063fbSHans Petter Selasky };
35118063fbSHans Petter Selasky 
368abf5ac0SHans Petter Selasky static const char *mlx5_ib_cong_status_desc[] = {
378abf5ac0SHans Petter Selasky 	MLX5_IB_CONG_STATUS(MLX5_IB_STATS_DESC)
388abf5ac0SHans Petter Selasky };
398abf5ac0SHans Petter Selasky 
40118063fbSHans Petter Selasky static const char *mlx5_ib_cong_stats_desc[] = {
41118063fbSHans Petter Selasky 	MLX5_IB_CONG_STATS(MLX5_IB_STATS_DESC)
42118063fbSHans Petter Selasky };
43118063fbSHans Petter Selasky 
449b6e45d4SHans Petter Selasky #define	MLX5_IB_INDEX(field) ( \
459b6e45d4SHans Petter Selasky     (__offsetof(struct mlx5_ib_congestion, field) - \
469b6e45d4SHans Petter Selasky      __offsetof(struct mlx5_ib_congestion, arg[0])) / sizeof(u64))
47118063fbSHans Petter Selasky #define	MLX5_IB_FLD_MAX(type, field) ((1ULL << __mlx5_bit_sz(type, field)) - 1ULL)
48118063fbSHans Petter Selasky #define	MLX5_IB_SET_CLIPPED(type, ptr, field, var) do { \
49118063fbSHans Petter Selasky   /* rangecheck */					\
50118063fbSHans Petter Selasky   if ((var) > MLX5_IB_FLD_MAX(type, field))		\
51118063fbSHans Petter Selasky 	(var) = MLX5_IB_FLD_MAX(type, field);		\
52118063fbSHans Petter Selasky   /* set value */					\
53118063fbSHans Petter Selasky   MLX5_SET(type, ptr, field, var);			\
54118063fbSHans Petter Selasky } while (0)
55118063fbSHans Petter Selasky 
56118063fbSHans Petter Selasky #define	CONG_LOCK(dev) sx_xlock(&(dev)->congestion.lock)
57118063fbSHans Petter Selasky #define	CONG_UNLOCK(dev) sx_xunlock(&(dev)->congestion.lock)
58118063fbSHans Petter Selasky #define	CONG_LOCKED(dev) sx_xlocked(&(dev)->congestion.lock)
59118063fbSHans Petter Selasky 
60118063fbSHans Petter Selasky #define	MLX5_IB_RP_CLAMP_TGT_RATE_ATTR			BIT(1)
61118063fbSHans Petter Selasky #define	MLX5_IB_RP_CLAMP_TGT_RATE_ATI_ATTR		BIT(2)
62118063fbSHans Petter Selasky #define	MLX5_IB_RP_TIME_RESET_ATTR			BIT(3)
63118063fbSHans Petter Selasky #define	MLX5_IB_RP_BYTE_RESET_ATTR			BIT(4)
64118063fbSHans Petter Selasky #define	MLX5_IB_RP_THRESHOLD_ATTR			BIT(5)
65118063fbSHans Petter Selasky #define	MLX5_IB_RP_AI_RATE_ATTR				BIT(7)
66118063fbSHans Petter Selasky #define	MLX5_IB_RP_HAI_RATE_ATTR			BIT(8)
67118063fbSHans Petter Selasky #define	MLX5_IB_RP_MIN_DEC_FAC_ATTR			BIT(9)
68118063fbSHans Petter Selasky #define	MLX5_IB_RP_MIN_RATE_ATTR			BIT(10)
69118063fbSHans Petter Selasky #define	MLX5_IB_RP_RATE_TO_SET_ON_FIRST_CNP_ATTR	BIT(11)
70118063fbSHans Petter Selasky #define	MLX5_IB_RP_DCE_TCP_G_ATTR			BIT(12)
71118063fbSHans Petter Selasky #define	MLX5_IB_RP_DCE_TCP_RTT_ATTR			BIT(13)
72118063fbSHans Petter Selasky #define	MLX5_IB_RP_RATE_REDUCE_MONITOR_PERIOD_ATTR	BIT(14)
73118063fbSHans Petter Selasky #define	MLX5_IB_RP_INITIAL_ALPHA_VALUE_ATTR		BIT(15)
74118063fbSHans Petter Selasky #define	MLX5_IB_RP_GD_ATTR				BIT(16)
75118063fbSHans Petter Selasky 
76118063fbSHans Petter Selasky #define	MLX5_IB_NP_CNP_DSCP_ATTR			BIT(3)
77118063fbSHans Petter Selasky #define	MLX5_IB_NP_CNP_PRIO_MODE_ATTR			BIT(4)
78118063fbSHans Petter Selasky 
79118063fbSHans Petter Selasky enum mlx5_ib_cong_node_type {
80118063fbSHans Petter Selasky 	MLX5_IB_RROCE_ECN_RP = 1,
81118063fbSHans Petter Selasky 	MLX5_IB_RROCE_ECN_NP = 2,
82118063fbSHans Petter Selasky };
83118063fbSHans Petter Selasky 
84118063fbSHans Petter Selasky static enum mlx5_ib_cong_node_type
mlx5_ib_param_to_node(u32 index)85118063fbSHans Petter Selasky mlx5_ib_param_to_node(u32 index)
86118063fbSHans Petter Selasky {
87118063fbSHans Petter Selasky 
88118063fbSHans Petter Selasky 	if (index >= MLX5_IB_INDEX(rp_clamp_tgt_rate) &&
89118063fbSHans Petter Selasky 	    index <= MLX5_IB_INDEX(rp_gd))
90118063fbSHans Petter Selasky 		return MLX5_IB_RROCE_ECN_RP;
91118063fbSHans Petter Selasky 	else
92118063fbSHans Petter Selasky 		return MLX5_IB_RROCE_ECN_NP;
93118063fbSHans Petter Selasky }
94118063fbSHans Petter Selasky 
95118063fbSHans Petter Selasky static u64
mlx5_get_cc_param_val(void * field,u32 index)96118063fbSHans Petter Selasky mlx5_get_cc_param_val(void *field, u32 index)
97118063fbSHans Petter Selasky {
98118063fbSHans Petter Selasky 
99118063fbSHans Petter Selasky 	switch (index) {
100118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_clamp_tgt_rate):
101118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
102118063fbSHans Petter Selasky 				clamp_tgt_rate);
103118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_clamp_tgt_rate_ati):
104118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
105118063fbSHans Petter Selasky 				clamp_tgt_rate_after_time_inc);
106118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_time_reset):
107118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
108118063fbSHans Petter Selasky 				rpg_time_reset);
109118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_byte_reset):
110118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
111118063fbSHans Petter Selasky 				rpg_byte_reset);
112118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_threshold):
113118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
114118063fbSHans Petter Selasky 				rpg_threshold);
115118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_ai_rate):
116118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
117118063fbSHans Petter Selasky 				rpg_ai_rate);
118118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_hai_rate):
119118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
120118063fbSHans Petter Selasky 				rpg_hai_rate);
121118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_min_dec_fac):
122118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
123118063fbSHans Petter Selasky 				rpg_min_dec_fac);
124118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_min_rate):
125118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
126118063fbSHans Petter Selasky 				rpg_min_rate);
127118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_rate_to_set_on_first_cnp):
128118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
129118063fbSHans Petter Selasky 				rate_to_set_on_first_cnp);
130118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_dce_tcp_g):
131118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
132118063fbSHans Petter Selasky 				dce_tcp_g);
133118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_dce_tcp_rtt):
134118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
135118063fbSHans Petter Selasky 				dce_tcp_rtt);
136118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_rate_reduce_monitor_period):
137118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
138118063fbSHans Petter Selasky 				rate_reduce_monitor_period);
139118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_initial_alpha_value):
140118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
141118063fbSHans Petter Selasky 				initial_alpha_value);
142118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_gd):
143118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_rp, field,
144118063fbSHans Petter Selasky 				rpg_gd);
145118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(np_cnp_dscp):
146118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_np, field,
147118063fbSHans Petter Selasky 				cnp_dscp);
148118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(np_cnp_prio_mode):
149118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_np, field,
150118063fbSHans Petter Selasky 				cnp_prio_mode);
151118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(np_cnp_prio):
152118063fbSHans Petter Selasky 		return MLX5_GET(cong_control_r_roce_ecn_np, field,
153118063fbSHans Petter Selasky 				cnp_802p_prio);
154118063fbSHans Petter Selasky 	default:
155118063fbSHans Petter Selasky 		return 0;
156118063fbSHans Petter Selasky 	}
157118063fbSHans Petter Selasky }
158118063fbSHans Petter Selasky 
159118063fbSHans Petter Selasky static void
mlx5_ib_set_cc_param_mask_val(void * field,u32 index,u64 var,u32 * attr_mask)160118063fbSHans Petter Selasky mlx5_ib_set_cc_param_mask_val(void *field, u32 index,
161118063fbSHans Petter Selasky     u64 var, u32 *attr_mask)
162118063fbSHans Petter Selasky {
163118063fbSHans Petter Selasky 
164118063fbSHans Petter Selasky 	switch (index) {
165118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_clamp_tgt_rate):
166118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_CLAMP_TGT_RATE_ATTR;
167118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
168118063fbSHans Petter Selasky 			 clamp_tgt_rate, var);
169118063fbSHans Petter Selasky 		break;
170118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_clamp_tgt_rate_ati):
171118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_CLAMP_TGT_RATE_ATI_ATTR;
172118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
173118063fbSHans Petter Selasky 			 clamp_tgt_rate_after_time_inc, var);
174118063fbSHans Petter Selasky 		break;
175118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_time_reset):
176118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_TIME_RESET_ATTR;
177118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
178118063fbSHans Petter Selasky 			 rpg_time_reset, var);
179118063fbSHans Petter Selasky 		break;
180118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_byte_reset):
181118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_BYTE_RESET_ATTR;
182118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
183118063fbSHans Petter Selasky 			 rpg_byte_reset, var);
184118063fbSHans Petter Selasky 		break;
185118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_threshold):
186118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_THRESHOLD_ATTR;
187118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
188118063fbSHans Petter Selasky 			 rpg_threshold, var);
189118063fbSHans Petter Selasky 		break;
190118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_ai_rate):
191118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_AI_RATE_ATTR;
192118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
193118063fbSHans Petter Selasky 			 rpg_ai_rate, var);
194118063fbSHans Petter Selasky 		break;
195118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_hai_rate):
196118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_HAI_RATE_ATTR;
197118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
198118063fbSHans Petter Selasky 			 rpg_hai_rate, var);
199118063fbSHans Petter Selasky 		break;
200118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_min_dec_fac):
201118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_MIN_DEC_FAC_ATTR;
202118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
203118063fbSHans Petter Selasky 			 rpg_min_dec_fac, var);
204118063fbSHans Petter Selasky 		break;
205118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_min_rate):
206118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_MIN_RATE_ATTR;
207118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
208118063fbSHans Petter Selasky 			 rpg_min_rate, var);
209118063fbSHans Petter Selasky 		break;
210118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_rate_to_set_on_first_cnp):
211118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_RATE_TO_SET_ON_FIRST_CNP_ATTR;
212118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
213118063fbSHans Petter Selasky 			 rate_to_set_on_first_cnp, var);
214118063fbSHans Petter Selasky 		break;
215118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_dce_tcp_g):
216118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_DCE_TCP_G_ATTR;
217118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
218118063fbSHans Petter Selasky 			 dce_tcp_g, var);
219118063fbSHans Petter Selasky 		break;
220118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_dce_tcp_rtt):
221118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_DCE_TCP_RTT_ATTR;
222118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
223118063fbSHans Petter Selasky 			 dce_tcp_rtt, var);
224118063fbSHans Petter Selasky 		break;
225118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_rate_reduce_monitor_period):
226118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_RATE_REDUCE_MONITOR_PERIOD_ATTR;
227118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
228118063fbSHans Petter Selasky 			 rate_reduce_monitor_period, var);
229118063fbSHans Petter Selasky 		break;
230118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_initial_alpha_value):
231118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_INITIAL_ALPHA_VALUE_ATTR;
232118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
233118063fbSHans Petter Selasky 			 initial_alpha_value, var);
234118063fbSHans Petter Selasky 		break;
235118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(rp_gd):
236118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_RP_GD_ATTR;
237118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_rp, field,
238118063fbSHans Petter Selasky 			 rpg_gd, var);
239118063fbSHans Petter Selasky 		break;
240118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(np_cnp_dscp):
241118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_NP_CNP_DSCP_ATTR;
242118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_np, field, cnp_dscp, var);
243118063fbSHans Petter Selasky 		break;
244118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(np_cnp_prio_mode):
245118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_NP_CNP_PRIO_MODE_ATTR;
246118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_np, field, cnp_prio_mode, var);
247118063fbSHans Petter Selasky 		break;
248118063fbSHans Petter Selasky 	case MLX5_IB_INDEX(np_cnp_prio):
249118063fbSHans Petter Selasky 		*attr_mask |= MLX5_IB_NP_CNP_PRIO_MODE_ATTR;
250118063fbSHans Petter Selasky 		MLX5_SET(cong_control_r_roce_ecn_np, field, cnp_prio_mode, 0);
251118063fbSHans Petter Selasky 		MLX5_IB_SET_CLIPPED(cong_control_r_roce_ecn_np, field, cnp_802p_prio, var);
252118063fbSHans Petter Selasky 		break;
253118063fbSHans Petter Selasky 	default:
254118063fbSHans Petter Selasky 		break;
255118063fbSHans Petter Selasky 	}
256118063fbSHans Petter Selasky }
257118063fbSHans Petter Selasky 
258118063fbSHans Petter Selasky static int
mlx5_ib_get_all_cc_params(struct mlx5_ib_dev * dev)259118063fbSHans Petter Selasky mlx5_ib_get_all_cc_params(struct mlx5_ib_dev *dev)
260118063fbSHans Petter Selasky {
261118063fbSHans Petter Selasky 	int outlen = MLX5_ST_SZ_BYTES(query_cong_params_out);
262118063fbSHans Petter Selasky 	enum mlx5_ib_cong_node_type node = 0;
263118063fbSHans Petter Selasky 	void *out;
264118063fbSHans Petter Selasky 	void *field;
265118063fbSHans Petter Selasky 	u32 x;
266118063fbSHans Petter Selasky 	int err = 0;
267118063fbSHans Petter Selasky 
268118063fbSHans Petter Selasky 	out = kzalloc(outlen, GFP_KERNEL);
269118063fbSHans Petter Selasky 	if (!out)
270118063fbSHans Petter Selasky 		return -ENOMEM;
271118063fbSHans Petter Selasky 
272118063fbSHans Petter Selasky 	/* get the current values */
273118063fbSHans Petter Selasky 	for (x = 0; x != MLX5_IB_CONG_PARAMS_NUM; x++) {
274118063fbSHans Petter Selasky 		if (node != mlx5_ib_param_to_node(x)) {
275118063fbSHans Petter Selasky 			node = mlx5_ib_param_to_node(x);
276118063fbSHans Petter Selasky 
277118063fbSHans Petter Selasky 			err = mlx5_cmd_query_cong_params(dev->mdev, node, out, outlen);
278118063fbSHans Petter Selasky 			if (err)
279118063fbSHans Petter Selasky 				break;
280118063fbSHans Petter Selasky 		}
281118063fbSHans Petter Selasky 		field = MLX5_ADDR_OF(query_cong_params_out, out, congestion_parameters);
282118063fbSHans Petter Selasky 		dev->congestion.arg[x] = mlx5_get_cc_param_val(field, x);
283118063fbSHans Petter Selasky 	}
284118063fbSHans Petter Selasky 	kfree(out);
285118063fbSHans Petter Selasky 	return err;
286118063fbSHans Petter Selasky }
287118063fbSHans Petter Selasky 
288118063fbSHans Petter Selasky static int
mlx5_ib_set_cc_params(struct mlx5_ib_dev * dev,u32 index,u64 var)289118063fbSHans Petter Selasky mlx5_ib_set_cc_params(struct mlx5_ib_dev *dev, u32 index, u64 var)
290118063fbSHans Petter Selasky {
291118063fbSHans Petter Selasky 	int inlen = MLX5_ST_SZ_BYTES(modify_cong_params_in);
292118063fbSHans Petter Selasky 	enum mlx5_ib_cong_node_type node;
293118063fbSHans Petter Selasky 	u32 attr_mask = 0;
294118063fbSHans Petter Selasky 	void *field;
295118063fbSHans Petter Selasky 	void *in;
296118063fbSHans Petter Selasky 	int err;
297118063fbSHans Petter Selasky 
298118063fbSHans Petter Selasky 	in = kzalloc(inlen, GFP_KERNEL);
299118063fbSHans Petter Selasky 	if (!in)
300118063fbSHans Petter Selasky 		return -ENOMEM;
301118063fbSHans Petter Selasky 
302118063fbSHans Petter Selasky 	MLX5_SET(modify_cong_params_in, in, opcode,
303118063fbSHans Petter Selasky 		 MLX5_CMD_OP_MODIFY_CONG_PARAMS);
304118063fbSHans Petter Selasky 
305118063fbSHans Petter Selasky 	node = mlx5_ib_param_to_node(index);
306118063fbSHans Petter Selasky 	MLX5_SET(modify_cong_params_in, in, cong_protocol, node);
307118063fbSHans Petter Selasky 
308118063fbSHans Petter Selasky 	field = MLX5_ADDR_OF(modify_cong_params_in, in, congestion_parameters);
309118063fbSHans Petter Selasky 	mlx5_ib_set_cc_param_mask_val(field, index, var, &attr_mask);
310118063fbSHans Petter Selasky 
311118063fbSHans Petter Selasky 	field = MLX5_ADDR_OF(modify_cong_params_in, in, field_select);
312118063fbSHans Petter Selasky 	MLX5_SET(field_select_r_roce_rp, field, field_select_r_roce_rp,
313118063fbSHans Petter Selasky 		 attr_mask);
314118063fbSHans Petter Selasky 
315118063fbSHans Petter Selasky 	err = mlx5_cmd_modify_cong_params(dev->mdev, in, inlen);
316118063fbSHans Petter Selasky 	kfree(in);
317118063fbSHans Petter Selasky 
318118063fbSHans Petter Selasky 	return err;
319118063fbSHans Petter Selasky }
320118063fbSHans Petter Selasky 
321118063fbSHans Petter Selasky static int
mlx5_ib_cong_params_handler(SYSCTL_HANDLER_ARGS)322118063fbSHans Petter Selasky mlx5_ib_cong_params_handler(SYSCTL_HANDLER_ARGS)
323118063fbSHans Petter Selasky {
324118063fbSHans Petter Selasky 	struct mlx5_ib_dev *dev = arg1;
325118063fbSHans Petter Selasky 	u64 value;
326118063fbSHans Petter Selasky 	int error;
327118063fbSHans Petter Selasky 
328118063fbSHans Petter Selasky 	CONG_LOCK(dev);
329118063fbSHans Petter Selasky 	value = dev->congestion.arg[arg2];
330118063fbSHans Petter Selasky 	if (req != NULL) {
331118063fbSHans Petter Selasky 		error = sysctl_handle_64(oidp, &value, 0, req);
332118063fbSHans Petter Selasky 		if (error || req->newptr == NULL ||
333118063fbSHans Petter Selasky 		    value == dev->congestion.arg[arg2])
334118063fbSHans Petter Selasky 			goto done;
335118063fbSHans Petter Selasky 
336118063fbSHans Petter Selasky 		/* assign new value */
337118063fbSHans Petter Selasky 		dev->congestion.arg[arg2] = value;
338118063fbSHans Petter Selasky 	} else {
339118063fbSHans Petter Selasky 		error = 0;
340118063fbSHans Petter Selasky 	}
341118063fbSHans Petter Selasky 	if (!MLX5_CAP_GEN(dev->mdev, cc_modify_allowed))
342118063fbSHans Petter Selasky 		error = EPERM;
343118063fbSHans Petter Selasky 	else {
344118063fbSHans Petter Selasky 		error = -mlx5_ib_set_cc_params(dev, MLX5_IB_INDEX(arg[arg2]),
345118063fbSHans Petter Selasky 		    dev->congestion.arg[arg2]);
346118063fbSHans Petter Selasky 	}
347118063fbSHans Petter Selasky done:
348118063fbSHans Petter Selasky 	CONG_UNLOCK(dev);
349118063fbSHans Petter Selasky 
350118063fbSHans Petter Selasky 	return (error);
351118063fbSHans Petter Selasky }
352118063fbSHans Petter Selasky 
3538abf5ac0SHans Petter Selasky static int
mlx5_ib_get_all_cc_status(struct mlx5_ib_dev * dev)3548abf5ac0SHans Petter Selasky mlx5_ib_get_all_cc_status(struct mlx5_ib_dev *dev)
3558abf5ac0SHans Petter Selasky {
3568abf5ac0SHans Petter Selasky 	const int outlen = MLX5_ST_SZ_BYTES(query_cong_status_out);
3578abf5ac0SHans Petter Selasky 	uint32_t out[MLX5_ST_SZ_DW(query_cong_status_out)] = {};
3588abf5ac0SHans Petter Selasky 	int error;
3598abf5ac0SHans Petter Selasky 
3608abf5ac0SHans Petter Selasky #define	MLX5_IB_CONG_STATUS_READ(a,b,c,d,e,node,prio,field) do { \
3618abf5ac0SHans Petter Selasky 	error = mlx5_cmd_query_cong_status(dev->mdev, node, prio, out, outlen); \
3628abf5ac0SHans Petter Selasky 	if (error)							\
3638abf5ac0SHans Petter Selasky 		goto done;						\
3648abf5ac0SHans Petter Selasky 	dev->congestion.c = MLX5_GET(query_cong_status_out, out, field); \
3658abf5ac0SHans Petter Selasky } while (0);
3668abf5ac0SHans Petter Selasky 
3678abf5ac0SHans Petter Selasky 	MLX5_IB_CONG_STATUS(MLX5_IB_CONG_STATUS_READ);
3688abf5ac0SHans Petter Selasky done:
3698abf5ac0SHans Petter Selasky 	return (error);
3708abf5ac0SHans Petter Selasky }
3718abf5ac0SHans Petter Selasky 
3728abf5ac0SHans Petter Selasky static int
mlx5_ib_cong_status_handler(SYSCTL_HANDLER_ARGS)3738abf5ac0SHans Petter Selasky mlx5_ib_cong_status_handler(SYSCTL_HANDLER_ARGS)
3748abf5ac0SHans Petter Selasky {
3758abf5ac0SHans Petter Selasky 	const int inlen = MLX5_ST_SZ_BYTES(modify_cong_status_in);
3768abf5ac0SHans Petter Selasky 	uint32_t in[MLX5_ST_SZ_DW(modify_cong_status_in)] = {};
3778abf5ac0SHans Petter Selasky 	struct mlx5_ib_dev *dev = arg1;
3788abf5ac0SHans Petter Selasky 	u64 value;
3798abf5ac0SHans Petter Selasky 	int error;
3808abf5ac0SHans Petter Selasky 
3818abf5ac0SHans Petter Selasky 	CONG_LOCK(dev);
3828abf5ac0SHans Petter Selasky 	value = dev->congestion.arg[arg2];
3838abf5ac0SHans Petter Selasky 	if (req != NULL) {
3848abf5ac0SHans Petter Selasky 		error = sysctl_handle_64(oidp, &value, 0, req);
3858abf5ac0SHans Petter Selasky 		/* convert value into a boolean */
3868abf5ac0SHans Petter Selasky 		value = value ? 1 : 0;
3878abf5ac0SHans Petter Selasky 		if (error || req->newptr == NULL ||
3888abf5ac0SHans Petter Selasky 		    value == dev->congestion.arg[arg2])
3898abf5ac0SHans Petter Selasky 			goto done;
3908abf5ac0SHans Petter Selasky 
3918abf5ac0SHans Petter Selasky 		/* assign new binary value */
3928abf5ac0SHans Petter Selasky 		dev->congestion.arg[arg2] = value;
3938abf5ac0SHans Petter Selasky 	} else {
3948abf5ac0SHans Petter Selasky 		error = 0;
3958abf5ac0SHans Petter Selasky 	}
3968abf5ac0SHans Petter Selasky 	if (!MLX5_CAP_GEN(dev->mdev, cc_modify_allowed))
3978abf5ac0SHans Petter Selasky 		error = EPERM;
3988abf5ac0SHans Petter Selasky 	else switch (arg2) {
3998abf5ac0SHans Petter Selasky #define	MLX5_IB_CONG_STATUS_WRITE(a,b,c,d,e,node,prio,field)	\
4008abf5ac0SHans Petter Selasky 	case MLX5_IB_INDEX(c):					\
4018abf5ac0SHans Petter Selasky 		MLX5_SET(modify_cong_status_in, in, opcode,	\
4028abf5ac0SHans Petter Selasky 		    MLX5_CMD_OP_MODIFY_CONG_STATUS);		\
4038abf5ac0SHans Petter Selasky 		MLX5_SET(modify_cong_status_in, in, priority, prio); \
4048abf5ac0SHans Petter Selasky 		MLX5_SET(modify_cong_status_in, in, cong_protocol, node); \
4058abf5ac0SHans Petter Selasky 		MLX5_SET(modify_cong_status_in, in, field, value); \
4068abf5ac0SHans Petter Selasky 		error = -mlx5_cmd_modify_cong_status(dev->mdev, in, inlen); \
4078abf5ac0SHans Petter Selasky 		break;
4088abf5ac0SHans Petter Selasky 	MLX5_IB_CONG_STATUS(MLX5_IB_CONG_STATUS_WRITE)
4098abf5ac0SHans Petter Selasky 	default:
4108abf5ac0SHans Petter Selasky 		error = EINVAL;
4118abf5ac0SHans Petter Selasky 		break;
4128abf5ac0SHans Petter Selasky 	}
4138abf5ac0SHans Petter Selasky done:
4148abf5ac0SHans Petter Selasky 	CONG_UNLOCK(dev);
4158abf5ac0SHans Petter Selasky 
4168abf5ac0SHans Petter Selasky 	return (error);
4178abf5ac0SHans Petter Selasky }
4188abf5ac0SHans Petter Selasky 
419118063fbSHans Petter Selasky #define	MLX5_GET_UNALIGNED_64(t,p,f) \
420118063fbSHans Petter Selasky     (((u64)MLX5_GET(t,p,f##_high) << 32) | MLX5_GET(t,p,f##_low))
421118063fbSHans Petter Selasky 
422118063fbSHans Petter Selasky static void
mlx5_ib_read_cong_stats(struct work_struct * work)423118063fbSHans Petter Selasky mlx5_ib_read_cong_stats(struct work_struct *work)
424118063fbSHans Petter Selasky {
425118063fbSHans Petter Selasky 	struct mlx5_ib_dev *dev =
426118063fbSHans Petter Selasky 	    container_of(work, struct mlx5_ib_dev, congestion.dwork.work);
427118063fbSHans Petter Selasky 	const int outlen = MLX5_ST_SZ_BYTES(query_cong_statistics_out);
428118063fbSHans Petter Selasky 	void *out;
429118063fbSHans Petter Selasky 
430118063fbSHans Petter Selasky 	out = kzalloc(outlen, GFP_KERNEL);
431118063fbSHans Petter Selasky 	if (!out)
432118063fbSHans Petter Selasky 		goto done;
433118063fbSHans Petter Selasky 
434118063fbSHans Petter Selasky 	CONG_LOCK(dev);
435118063fbSHans Petter Selasky 	if (mlx5_cmd_query_cong_counter(dev->mdev, 0, out, outlen))
436118063fbSHans Petter Selasky 		memset(out, 0, outlen);
437118063fbSHans Petter Selasky 
438118063fbSHans Petter Selasky 	dev->congestion.syndrome =
439118063fbSHans Petter Selasky 	    MLX5_GET(query_cong_statistics_out, out, syndrome);
440118063fbSHans Petter Selasky 	dev->congestion.rp_cur_flows =
441118063fbSHans Petter Selasky 	    MLX5_GET(query_cong_statistics_out, out, rp_cur_flows);
442118063fbSHans Petter Selasky 	dev->congestion.sum_flows =
443118063fbSHans Petter Selasky 	    MLX5_GET(query_cong_statistics_out, out, sum_flows);
444118063fbSHans Petter Selasky 	dev->congestion.rp_cnp_ignored =
445118063fbSHans Petter Selasky 	    MLX5_GET_UNALIGNED_64(query_cong_statistics_out, out, rp_cnp_ignored);
446118063fbSHans Petter Selasky 	dev->congestion.rp_cnp_handled =
447118063fbSHans Petter Selasky 	    MLX5_GET_UNALIGNED_64(query_cong_statistics_out, out, rp_cnp_handled);
448118063fbSHans Petter Selasky 	dev->congestion.time_stamp =
449118063fbSHans Petter Selasky 	    MLX5_GET_UNALIGNED_64(query_cong_statistics_out, out, time_stamp);
450118063fbSHans Petter Selasky 	dev->congestion.accumulators_period =
451118063fbSHans Petter Selasky 	    MLX5_GET(query_cong_statistics_out, out, accumulators_period);
452118063fbSHans Petter Selasky 	dev->congestion.np_ecn_marked_roce_packets =
453118063fbSHans Petter Selasky 	    MLX5_GET_UNALIGNED_64(query_cong_statistics_out, out, np_ecn_marked_roce_packets);
454118063fbSHans Petter Selasky 	dev->congestion.np_cnp_sent =
455118063fbSHans Petter Selasky 	    MLX5_GET_UNALIGNED_64(query_cong_statistics_out, out, np_cnp_sent);
456118063fbSHans Petter Selasky 
457118063fbSHans Petter Selasky 	CONG_UNLOCK(dev);
458118063fbSHans Petter Selasky 	kfree(out);
459118063fbSHans Petter Selasky 
460118063fbSHans Petter Selasky done:
461118063fbSHans Petter Selasky 	schedule_delayed_work(&dev->congestion.dwork, hz);
462118063fbSHans Petter Selasky }
463118063fbSHans Petter Selasky 
464118063fbSHans Petter Selasky void
mlx5_ib_cleanup_congestion(struct mlx5_ib_dev * dev)465118063fbSHans Petter Selasky mlx5_ib_cleanup_congestion(struct mlx5_ib_dev *dev)
466118063fbSHans Petter Selasky {
467118063fbSHans Petter Selasky 
468d3300d4aSSlava Shwartsman 	while (cancel_delayed_work_sync(&dev->congestion.dwork))
469d3300d4aSSlava Shwartsman 		;
470118063fbSHans Petter Selasky 	sysctl_ctx_free(&dev->congestion.ctx);
471118063fbSHans Petter Selasky 	sx_destroy(&dev->congestion.lock);
472118063fbSHans Petter Selasky }
473118063fbSHans Petter Selasky 
474118063fbSHans Petter Selasky int
mlx5_ib_init_congestion(struct mlx5_ib_dev * dev)475118063fbSHans Petter Selasky mlx5_ib_init_congestion(struct mlx5_ib_dev *dev)
476118063fbSHans Petter Selasky {
477118063fbSHans Petter Selasky 	struct sysctl_ctx_list *ctx;
478118063fbSHans Petter Selasky 	struct sysctl_oid *parent;
479118063fbSHans Petter Selasky 	struct sysctl_oid *node;
480118063fbSHans Petter Selasky 	int err;
481118063fbSHans Petter Selasky 	u32 x;
482118063fbSHans Petter Selasky 
483118063fbSHans Petter Selasky 	ctx = &dev->congestion.ctx;
484118063fbSHans Petter Selasky 	sysctl_ctx_init(ctx);
485118063fbSHans Petter Selasky 	sx_init(&dev->congestion.lock, "mlx5ibcong");
486118063fbSHans Petter Selasky 	INIT_DELAYED_WORK(&dev->congestion.dwork, mlx5_ib_read_cong_stats);
487118063fbSHans Petter Selasky 
488118063fbSHans Petter Selasky 	if (!MLX5_CAP_GEN(dev->mdev, cc_query_allowed))
489118063fbSHans Petter Selasky 		return (0);
490118063fbSHans Petter Selasky 
491118063fbSHans Petter Selasky 	err = mlx5_ib_get_all_cc_params(dev);
492118063fbSHans Petter Selasky 	if (err)
493118063fbSHans Petter Selasky 		return (err);
494118063fbSHans Petter Selasky 
4958abf5ac0SHans Petter Selasky 	err = mlx5_ib_get_all_cc_status(dev);
4968abf5ac0SHans Petter Selasky 	if (err)
4978abf5ac0SHans Petter Selasky 		return (err);
4988abf5ac0SHans Petter Selasky 
499118063fbSHans Petter Selasky 	parent = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(dev->ib_dev.dev.kobj.oidp),
5007029da5cSPawel Biernacki 	    OID_AUTO, "cong", CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
5017029da5cSPawel Biernacki 	    "Congestion control");
502118063fbSHans Petter Selasky 	if (parent == NULL)
503118063fbSHans Petter Selasky 		return (-ENOMEM);
504118063fbSHans Petter Selasky 
505118063fbSHans Petter Selasky 	node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(parent),
5067029da5cSPawel Biernacki 	    OID_AUTO, "conf", CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
5077029da5cSPawel Biernacki 	    "Configuration");
508118063fbSHans Petter Selasky 	if (node == NULL) {
509118063fbSHans Petter Selasky 		sysctl_ctx_free(&dev->congestion.ctx);
510118063fbSHans Petter Selasky 		return (-ENOMEM);
511118063fbSHans Petter Selasky 	}
512118063fbSHans Petter Selasky 
513118063fbSHans Petter Selasky 	for (x = 0; x != MLX5_IB_CONG_PARAMS_NUM; x++) {
514118063fbSHans Petter Selasky 		SYSCTL_ADD_PROC(ctx,
515118063fbSHans Petter Selasky 		    SYSCTL_CHILDREN(node), OID_AUTO,
516118063fbSHans Petter Selasky 		    mlx5_ib_cong_params_desc[2 * x],
517118063fbSHans Petter Selasky 		    CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
518118063fbSHans Petter Selasky 		    dev, x, &mlx5_ib_cong_params_handler, "QU",
519118063fbSHans Petter Selasky 		    mlx5_ib_cong_params_desc[2 * x + 1]);
520118063fbSHans Petter Selasky 	}
521118063fbSHans Petter Selasky 
5228abf5ac0SHans Petter Selasky 	for (x = 0; x != MLX5_IB_CONG_STATUS_NUM; x++) {
5238abf5ac0SHans Petter Selasky 		SYSCTL_ADD_PROC(ctx,
5248abf5ac0SHans Petter Selasky 		    SYSCTL_CHILDREN(node), OID_AUTO,
5258abf5ac0SHans Petter Selasky 		    mlx5_ib_cong_status_desc[2 * x],
5268abf5ac0SHans Petter Selasky 		    CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
5278abf5ac0SHans Petter Selasky 		    dev, x + MLX5_IB_CONG_PARAMS_NUM + MLX5_IB_CONG_STATS_NUM,
5288abf5ac0SHans Petter Selasky 		    &mlx5_ib_cong_status_handler, "QU",
5298abf5ac0SHans Petter Selasky 		    mlx5_ib_cong_status_desc[2 * x + 1]);
5308abf5ac0SHans Petter Selasky 	}
5318abf5ac0SHans Petter Selasky 
532118063fbSHans Petter Selasky 	node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(parent),
5337029da5cSPawel Biernacki 	    OID_AUTO, "stats", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
5347029da5cSPawel Biernacki 	    "Statistics");
535118063fbSHans Petter Selasky 	if (node == NULL) {
536118063fbSHans Petter Selasky 		sysctl_ctx_free(&dev->congestion.ctx);
537118063fbSHans Petter Selasky 		return (-ENOMEM);
538118063fbSHans Petter Selasky 	}
539118063fbSHans Petter Selasky 
540118063fbSHans Petter Selasky 	for (x = 0; x != MLX5_IB_CONG_STATS_NUM; x++) {
541118063fbSHans Petter Selasky 		/* read-only SYSCTLs */
542118063fbSHans Petter Selasky 		SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
543118063fbSHans Petter Selasky 		    mlx5_ib_cong_stats_desc[2 * x],
544118063fbSHans Petter Selasky 		    CTLFLAG_RD | CTLFLAG_MPSAFE,
545118063fbSHans Petter Selasky 		    &dev->congestion.arg[x + MLX5_IB_CONG_PARAMS_NUM],
546118063fbSHans Petter Selasky 		    0, mlx5_ib_cong_stats_desc[2 * x + 1]);
547118063fbSHans Petter Selasky 	}
548118063fbSHans Petter Selasky 	schedule_delayed_work(&dev->congestion.dwork, hz);
549118063fbSHans Petter Selasky 	return (0);
550118063fbSHans Petter Selasky }
551