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
];
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 net_device
*netdev
,
131 struct ieee_ets
*ets
)
136 /* Validate Priority */
137 for (i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++) {
138 if (ets
->prio_tc
[i
] >= MLX5E_MAX_PRIORITY
) {
140 "Failed to validate ETS: priority value greater than max(%d)\n",
146 /* Validate Bandwidth Sum */
147 for (i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++) {
148 if (ets
->tc_tsa
[i
] == IEEE_8021QAZ_TSA_ETS
) {
149 if (!ets
->tc_tx_bw
[i
]) {
151 "Failed to validate ETS: BW 0 is illegal\n");
155 bw_sum
+= ets
->tc_tx_bw
[i
];
159 if (bw_sum
!= 0 && bw_sum
!= 100) {
161 "Failed to validate ETS: BW sum is illegal\n");
167 static int mlx5e_dcbnl_ieee_setets(struct net_device
*netdev
,
168 struct ieee_ets
*ets
)
170 struct mlx5e_priv
*priv
= netdev_priv(netdev
);
173 err
= mlx5e_dbcnl_validate_ets(netdev
, ets
);
177 err
= mlx5e_dcbnl_ieee_setets_core(priv
, ets
);
181 memcpy(&priv
->params
.ets
, ets
, sizeof(*ets
));
182 priv
->params
.ets
.ets_cap
= mlx5_max_tc(priv
->mdev
) + 1;
187 static int mlx5e_dcbnl_ieee_getpfc(struct net_device
*dev
,
188 struct ieee_pfc
*pfc
)
190 struct mlx5e_priv
*priv
= netdev_priv(dev
);
191 struct mlx5_core_dev
*mdev
= priv
->mdev
;
192 struct mlx5e_pport_stats
*pstats
= &priv
->stats
.pport
;
195 pfc
->pfc_cap
= mlx5_max_tc(mdev
) + 1;
196 for (i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++) {
197 pfc
->requests
[i
] = PPORT_PER_PRIO_GET(pstats
, i
, tx_pause
);
198 pfc
->indications
[i
] = PPORT_PER_PRIO_GET(pstats
, i
, rx_pause
);
201 return mlx5_query_port_pfc(mdev
, &pfc
->pfc_en
, NULL
);
204 static int mlx5e_dcbnl_ieee_setpfc(struct net_device
*dev
,
205 struct ieee_pfc
*pfc
)
207 struct mlx5e_priv
*priv
= netdev_priv(dev
);
208 struct mlx5_core_dev
*mdev
= priv
->mdev
;
212 mlx5_query_port_pfc(mdev
, &curr_pfc_en
, NULL
);
214 if (pfc
->pfc_en
== curr_pfc_en
)
217 ret
= mlx5_set_port_pfc(mdev
, pfc
->pfc_en
, pfc
->pfc_en
);
218 mlx5_toggle_port_link(mdev
);
223 static u8
mlx5e_dcbnl_getdcbx(struct net_device
*dev
)
225 return DCB_CAP_DCBX_HOST
| DCB_CAP_DCBX_VER_IEEE
;
228 static u8
mlx5e_dcbnl_setdcbx(struct net_device
*dev
, u8 mode
)
230 if ((mode
& DCB_CAP_DCBX_LLD_MANAGED
) ||
231 (mode
& DCB_CAP_DCBX_VER_CEE
) ||
232 !(mode
& DCB_CAP_DCBX_VER_IEEE
) ||
233 !(mode
& DCB_CAP_DCBX_HOST
))
239 static int mlx5e_dcbnl_ieee_getmaxrate(struct net_device
*netdev
,
240 struct ieee_maxrate
*maxrate
)
242 struct mlx5e_priv
*priv
= netdev_priv(netdev
);
243 struct mlx5_core_dev
*mdev
= priv
->mdev
;
244 u8 max_bw_value
[IEEE_8021QAZ_MAX_TCS
];
245 u8 max_bw_unit
[IEEE_8021QAZ_MAX_TCS
];
249 err
= mlx5_query_port_ets_rate_limit(mdev
, max_bw_value
, max_bw_unit
);
253 memset(maxrate
->tc_maxrate
, 0, sizeof(maxrate
->tc_maxrate
));
255 for (i
= 0; i
<= mlx5_max_tc(mdev
); i
++) {
256 switch (max_bw_unit
[i
]) {
257 case MLX5_100_MBPS_UNIT
:
258 maxrate
->tc_maxrate
[i
] = max_bw_value
[i
] * MLX5E_100MB
;
261 maxrate
->tc_maxrate
[i
] = max_bw_value
[i
] * MLX5E_1GB
;
263 case MLX5_BW_NO_LIMIT
:
266 WARN(true, "non-supported BW unit");
274 static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device
*netdev
,
275 struct ieee_maxrate
*maxrate
)
277 struct mlx5e_priv
*priv
= netdev_priv(netdev
);
278 struct mlx5_core_dev
*mdev
= priv
->mdev
;
279 u8 max_bw_value
[IEEE_8021QAZ_MAX_TCS
];
280 u8 max_bw_unit
[IEEE_8021QAZ_MAX_TCS
];
281 __u64 upper_limit_mbps
= roundup(255 * MLX5E_100MB
, MLX5E_1GB
);
284 memset(max_bw_value
, 0, sizeof(max_bw_value
));
285 memset(max_bw_unit
, 0, sizeof(max_bw_unit
));
287 for (i
= 0; i
<= mlx5_max_tc(mdev
); i
++) {
288 if (!maxrate
->tc_maxrate
[i
]) {
289 max_bw_unit
[i
] = MLX5_BW_NO_LIMIT
;
292 if (maxrate
->tc_maxrate
[i
] < upper_limit_mbps
) {
293 max_bw_value
[i
] = div_u64(maxrate
->tc_maxrate
[i
],
295 max_bw_value
[i
] = max_bw_value
[i
] ? max_bw_value
[i
] : 1;
296 max_bw_unit
[i
] = MLX5_100_MBPS_UNIT
;
298 max_bw_value
[i
] = div_u64(maxrate
->tc_maxrate
[i
],
300 max_bw_unit
[i
] = MLX5_GBPS_UNIT
;
304 return mlx5_modify_port_ets_rate_limit(mdev
, max_bw_value
, max_bw_unit
);
307 const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops
= {
308 .ieee_getets
= mlx5e_dcbnl_ieee_getets
,
309 .ieee_setets
= mlx5e_dcbnl_ieee_setets
,
310 .ieee_getmaxrate
= mlx5e_dcbnl_ieee_getmaxrate
,
311 .ieee_setmaxrate
= mlx5e_dcbnl_ieee_setmaxrate
,
312 .ieee_getpfc
= mlx5e_dcbnl_ieee_getpfc
,
313 .ieee_setpfc
= mlx5e_dcbnl_ieee_setpfc
,
314 .getdcbx
= mlx5e_dcbnl_getdcbx
,
315 .setdcbx
= mlx5e_dcbnl_setdcbx
,