2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 #include <linux/device.h>
33 #include <linux/netdevice.h>
36 #define MLX5E_MAX_PRIORITY 8
38 #define MLX5E_100MB (100000)
39 #define MLX5E_1GB (1000000)
41 static int mlx5e_dcbnl_ieee_getets(struct net_device
*netdev
,
44 struct mlx5e_priv
*priv
= netdev_priv(netdev
);
46 if (!MLX5_CAP_GEN(priv
->mdev
, ets
))
49 memcpy(ets
, &priv
->params
.ets
, sizeof(*ets
));
54 MLX5E_VENDOR_TC_GROUP_NUM
= 7,
55 MLX5E_ETS_TC_GROUP_NUM
= 0,
58 static void mlx5e_build_tc_group(struct ieee_ets
*ets
, u8
*tc_group
, int max_tc
)
60 bool any_tc_mapped_to_ets
= false;
64 for (i
= 0; i
<= max_tc
; i
++)
65 if (ets
->tc_tsa
[i
] == IEEE_8021QAZ_TSA_ETS
)
66 any_tc_mapped_to_ets
= true;
68 strict_group
= any_tc_mapped_to_ets
? 1 : 0;
70 for (i
= 0; i
<= max_tc
; i
++) {
71 switch (ets
->tc_tsa
[i
]) {
72 case IEEE_8021QAZ_TSA_VENDOR
:
73 tc_group
[i
] = MLX5E_VENDOR_TC_GROUP_NUM
;
75 case IEEE_8021QAZ_TSA_STRICT
:
76 tc_group
[i
] = strict_group
++;
78 case IEEE_8021QAZ_TSA_ETS
:
79 tc_group
[i
] = MLX5E_ETS_TC_GROUP_NUM
;
85 static void mlx5e_build_tc_tx_bw(struct ieee_ets
*ets
, u8
*tc_tx_bw
,
86 u8
*tc_group
, int max_tc
)
90 for (i
= 0; i
<= max_tc
; i
++) {
91 switch (ets
->tc_tsa
[i
]) {
92 case IEEE_8021QAZ_TSA_VENDOR
:
93 tc_tx_bw
[i
] = MLX5E_MAX_BW_ALLOC
;
95 case IEEE_8021QAZ_TSA_STRICT
:
96 tc_tx_bw
[i
] = MLX5E_MAX_BW_ALLOC
;
98 case IEEE_8021QAZ_TSA_ETS
:
99 tc_tx_bw
[i
] = ets
->tc_tx_bw
[i
] ?: MLX5E_MIN_BW_ALLOC
;
105 int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv
*priv
, struct ieee_ets
*ets
)
107 struct mlx5_core_dev
*mdev
= priv
->mdev
;
108 u8 tc_tx_bw
[IEEE_8021QAZ_MAX_TCS
];
109 u8 tc_group
[IEEE_8021QAZ_MAX_TCS
];
110 int max_tc
= mlx5_max_tc(mdev
);
113 if (!MLX5_CAP_GEN(mdev
, ets
))
116 mlx5e_build_tc_group(ets
, tc_group
, max_tc
);
117 mlx5e_build_tc_tx_bw(ets
, tc_tx_bw
, tc_group
, max_tc
);
119 err
= mlx5_set_port_prio_tc(mdev
, ets
->prio_tc
);
123 err
= mlx5_set_port_tc_group(mdev
, tc_group
);
127 return mlx5_set_port_tc_bw_alloc(mdev
, tc_tx_bw
);
130 static int mlx5e_dbcnl_validate_ets(struct ieee_ets
*ets
)
135 /* Validate Priority */
136 for (i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++) {
137 if (ets
->prio_tc
[i
] >= MLX5E_MAX_PRIORITY
)
141 /* Validate Bandwidth Sum */
142 for (i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++) {
143 if (ets
->tc_tsa
[i
] == IEEE_8021QAZ_TSA_ETS
)
144 bw_sum
+= ets
->tc_tx_bw
[i
];
147 if (bw_sum
!= 0 && bw_sum
!= 100)
152 static int mlx5e_dcbnl_ieee_setets(struct net_device
*netdev
,
153 struct ieee_ets
*ets
)
155 struct mlx5e_priv
*priv
= netdev_priv(netdev
);
158 err
= mlx5e_dbcnl_validate_ets(ets
);
162 err
= mlx5e_dcbnl_ieee_setets_core(priv
, ets
);
166 memcpy(&priv
->params
.ets
, ets
, sizeof(*ets
));
167 priv
->params
.ets
.ets_cap
= mlx5_max_tc(priv
->mdev
) + 1;
172 static int mlx5e_dcbnl_ieee_getpfc(struct net_device
*dev
,
173 struct ieee_pfc
*pfc
)
175 struct mlx5e_priv
*priv
= netdev_priv(dev
);
176 struct mlx5_core_dev
*mdev
= priv
->mdev
;
177 struct mlx5e_pport_stats
*pstats
= &priv
->stats
.pport
;
180 pfc
->pfc_cap
= mlx5_max_tc(mdev
) + 1;
181 for (i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++) {
182 pfc
->requests
[i
] = PPORT_PER_PRIO_GET(pstats
, i
, tx_pause
);
183 pfc
->indications
[i
] = PPORT_PER_PRIO_GET(pstats
, i
, rx_pause
);
186 return mlx5_query_port_pfc(mdev
, &pfc
->pfc_en
, NULL
);
189 static int mlx5e_dcbnl_ieee_setpfc(struct net_device
*dev
,
190 struct ieee_pfc
*pfc
)
192 struct mlx5e_priv
*priv
= netdev_priv(dev
);
193 struct mlx5_core_dev
*mdev
= priv
->mdev
;
194 enum mlx5_port_status ps
;
198 mlx5_query_port_pfc(mdev
, &curr_pfc_en
, NULL
);
200 if (pfc
->pfc_en
== curr_pfc_en
)
203 mlx5_query_port_admin_status(mdev
, &ps
);
204 if (ps
== MLX5_PORT_UP
)
205 mlx5_set_port_admin_status(mdev
, MLX5_PORT_DOWN
);
207 ret
= mlx5_set_port_pfc(mdev
, pfc
->pfc_en
, pfc
->pfc_en
);
209 if (ps
== MLX5_PORT_UP
)
210 mlx5_set_port_admin_status(mdev
, MLX5_PORT_UP
);
215 static u8
mlx5e_dcbnl_getdcbx(struct net_device
*dev
)
217 return DCB_CAP_DCBX_HOST
| DCB_CAP_DCBX_VER_IEEE
;
220 static u8
mlx5e_dcbnl_setdcbx(struct net_device
*dev
, u8 mode
)
222 if ((mode
& DCB_CAP_DCBX_LLD_MANAGED
) ||
223 (mode
& DCB_CAP_DCBX_VER_CEE
) ||
224 !(mode
& DCB_CAP_DCBX_VER_IEEE
) ||
225 !(mode
& DCB_CAP_DCBX_HOST
))
231 static int mlx5e_dcbnl_ieee_getmaxrate(struct net_device
*netdev
,
232 struct ieee_maxrate
*maxrate
)
234 struct mlx5e_priv
*priv
= netdev_priv(netdev
);
235 struct mlx5_core_dev
*mdev
= priv
->mdev
;
236 u8 max_bw_value
[IEEE_8021QAZ_MAX_TCS
];
237 u8 max_bw_unit
[IEEE_8021QAZ_MAX_TCS
];
241 err
= mlx5_query_port_ets_rate_limit(mdev
, max_bw_value
, max_bw_unit
);
245 memset(maxrate
->tc_maxrate
, 0, sizeof(maxrate
->tc_maxrate
));
247 for (i
= 0; i
<= mlx5_max_tc(mdev
); i
++) {
248 switch (max_bw_unit
[i
]) {
249 case MLX5_100_MBPS_UNIT
:
250 maxrate
->tc_maxrate
[i
] = max_bw_value
[i
] * MLX5E_100MB
;
253 maxrate
->tc_maxrate
[i
] = max_bw_value
[i
] * MLX5E_1GB
;
255 case MLX5_BW_NO_LIMIT
:
258 WARN(true, "non-supported BW unit");
266 static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device
*netdev
,
267 struct ieee_maxrate
*maxrate
)
269 struct mlx5e_priv
*priv
= netdev_priv(netdev
);
270 struct mlx5_core_dev
*mdev
= priv
->mdev
;
271 u8 max_bw_value
[IEEE_8021QAZ_MAX_TCS
];
272 u8 max_bw_unit
[IEEE_8021QAZ_MAX_TCS
];
273 __u64 upper_limit_mbps
= roundup(255 * MLX5E_100MB
, MLX5E_1GB
);
276 memset(max_bw_value
, 0, sizeof(max_bw_value
));
277 memset(max_bw_unit
, 0, sizeof(max_bw_unit
));
279 for (i
= 0; i
<= mlx5_max_tc(mdev
); i
++) {
280 if (!maxrate
->tc_maxrate
[i
]) {
281 max_bw_unit
[i
] = MLX5_BW_NO_LIMIT
;
284 if (maxrate
->tc_maxrate
[i
] < upper_limit_mbps
) {
285 max_bw_value
[i
] = div_u64(maxrate
->tc_maxrate
[i
],
287 max_bw_value
[i
] = max_bw_value
[i
] ? max_bw_value
[i
] : 1;
288 max_bw_unit
[i
] = MLX5_100_MBPS_UNIT
;
290 max_bw_value
[i
] = div_u64(maxrate
->tc_maxrate
[i
],
292 max_bw_unit
[i
] = MLX5_GBPS_UNIT
;
296 return mlx5_modify_port_ets_rate_limit(mdev
, max_bw_value
, max_bw_unit
);
299 const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops
= {
300 .ieee_getets
= mlx5e_dcbnl_ieee_getets
,
301 .ieee_setets
= mlx5e_dcbnl_ieee_setets
,
302 .ieee_getmaxrate
= mlx5e_dcbnl_ieee_getmaxrate
,
303 .ieee_setmaxrate
= mlx5e_dcbnl_ieee_setmaxrate
,
304 .ieee_getpfc
= mlx5e_dcbnl_ieee_getpfc
,
305 .ieee_setpfc
= mlx5e_dcbnl_ieee_setpfc
,
306 .getdcbx
= mlx5e_dcbnl_getdcbx
,
307 .setdcbx
= mlx5e_dcbnl_setdcbx
,