Commit | Line | Data |
---|---|---|
08fb1dac SM |
1 | /* |
2 | * Copyright (c) 2016, Mellanox Technologies. All rights reserved. | |
3 | * | |
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: | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or | |
11 | * without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistributions of source code must retain the above | |
15 | * copyright notice, this list of conditions and the following | |
16 | * disclaimer. | |
17 | * | |
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. | |
22 | * | |
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 | |
30 | * SOFTWARE. | |
31 | */ | |
32 | #include <linux/device.h> | |
33 | #include <linux/netdevice.h> | |
34 | #include "en.h" | |
35 | ||
36 | #define MLX5E_MAX_PRIORITY 8 | |
37 | ||
d8880795 TT |
38 | #define MLX5E_100MB (100000) |
39 | #define MLX5E_1GB (1000000) | |
40 | ||
3a6a931d HN |
41 | #define MLX5E_CEE_STATE_UP 1 |
42 | #define MLX5E_CEE_STATE_DOWN 0 | |
43 | ||
be0f161e HN |
44 | enum { |
45 | MLX5E_VENDOR_TC_GROUP_NUM = 7, | |
46 | MLX5E_LOWEST_PRIO_GROUP = 0, | |
47 | }; | |
48 | ||
2a5e7a13 HN |
49 | #define MLX5_DSCP_SUPPORTED(mdev) (MLX5_CAP_GEN(mdev, qcam_reg) && \ |
50 | MLX5_CAP_QCAM_REG(mdev, qpts) && \ | |
51 | MLX5_CAP_QCAM_REG(mdev, qpdpm)) | |
52 | ||
53 | static int mlx5e_set_trust_state(struct mlx5e_priv *priv, u8 trust_state); | |
54 | static int mlx5e_set_dscp2prio(struct mlx5e_priv *priv, u8 dscp, u8 prio); | |
55 | ||
e207b7e9 HN |
56 | /* If dcbx mode is non-host set the dcbx mode to host. |
57 | */ | |
58 | static int mlx5e_dcbnl_set_dcbx_mode(struct mlx5e_priv *priv, | |
59 | enum mlx5_dcbx_oper_mode mode) | |
60 | { | |
61 | struct mlx5_core_dev *mdev = priv->mdev; | |
62 | u32 param[MLX5_ST_SZ_DW(dcbx_param)]; | |
63 | int err; | |
64 | ||
65 | err = mlx5_query_port_dcbx_param(mdev, param); | |
66 | if (err) | |
67 | return err; | |
68 | ||
69 | MLX5_SET(dcbx_param, param, version_admin, mode); | |
70 | if (mode != MLX5E_DCBX_PARAM_VER_OPER_HOST) | |
71 | MLX5_SET(dcbx_param, param, willing_admin, 1); | |
72 | ||
73 | return mlx5_set_port_dcbx_param(mdev, param); | |
74 | } | |
75 | ||
76 | static int mlx5e_dcbnl_switch_to_host_mode(struct mlx5e_priv *priv) | |
77 | { | |
78 | struct mlx5e_dcbx *dcbx = &priv->dcbx; | |
79 | int err; | |
80 | ||
81 | if (!MLX5_CAP_GEN(priv->mdev, dcbx)) | |
82 | return 0; | |
83 | ||
84 | if (dcbx->mode == MLX5E_DCBX_PARAM_VER_OPER_HOST) | |
85 | return 0; | |
86 | ||
87 | err = mlx5e_dcbnl_set_dcbx_mode(priv, MLX5E_DCBX_PARAM_VER_OPER_HOST); | |
88 | if (err) | |
89 | return err; | |
90 | ||
91 | dcbx->mode = MLX5E_DCBX_PARAM_VER_OPER_HOST; | |
92 | return 0; | |
93 | } | |
94 | ||
08fb1dac SM |
95 | static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev, |
96 | struct ieee_ets *ets) | |
97 | { | |
98 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
820c2c5e | 99 | struct mlx5_core_dev *mdev = priv->mdev; |
be0f161e HN |
100 | u8 tc_group[IEEE_8021QAZ_MAX_TCS]; |
101 | bool is_tc_group_6_exist = false; | |
102 | bool is_zero_bw_ets_tc = false; | |
820c2c5e HN |
103 | int err = 0; |
104 | int i; | |
08fb1dac SM |
105 | |
106 | if (!MLX5_CAP_GEN(priv->mdev, ets)) | |
9eb78923 | 107 | return -EOPNOTSUPP; |
08fb1dac | 108 | |
820c2c5e HN |
109 | ets->ets_cap = mlx5_max_tc(priv->mdev) + 1; |
110 | for (i = 0; i < ets->ets_cap; i++) { | |
111 | err = mlx5_query_port_prio_tc(mdev, i, &ets->prio_tc[i]); | |
112 | if (err) | |
113 | return err; | |
820c2c5e | 114 | |
be0f161e HN |
115 | err = mlx5_query_port_tc_group(mdev, i, &tc_group[i]); |
116 | if (err) | |
117 | return err; | |
118 | ||
820c2c5e HN |
119 | err = mlx5_query_port_tc_bw_alloc(mdev, i, &ets->tc_tx_bw[i]); |
120 | if (err) | |
121 | return err; | |
be0f161e HN |
122 | |
123 | if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC && | |
124 | tc_group[i] == (MLX5E_LOWEST_PRIO_GROUP + 1)) | |
125 | is_zero_bw_ets_tc = true; | |
126 | ||
127 | if (tc_group[i] == (MLX5E_VENDOR_TC_GROUP_NUM - 1)) | |
128 | is_tc_group_6_exist = true; | |
129 | } | |
130 | ||
131 | /* Report 0% ets tc if exits*/ | |
132 | if (is_zero_bw_ets_tc) { | |
133 | for (i = 0; i < ets->ets_cap; i++) | |
134 | if (tc_group[i] == MLX5E_LOWEST_PRIO_GROUP) | |
135 | ets->tc_tx_bw[i] = 0; | |
136 | } | |
137 | ||
138 | /* Update tc_tsa based on fw setting*/ | |
139 | for (i = 0; i < ets->ets_cap; i++) { | |
820c2c5e HN |
140 | if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC) |
141 | priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; | |
be0f161e HN |
142 | else if (tc_group[i] == MLX5E_VENDOR_TC_GROUP_NUM && |
143 | !is_tc_group_6_exist) | |
144 | priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR; | |
820c2c5e | 145 | } |
820c2c5e HN |
146 | memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa)); |
147 | ||
148 | return err; | |
08fb1dac SM |
149 | } |
150 | ||
08fb1dac SM |
151 | static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc) |
152 | { | |
153 | bool any_tc_mapped_to_ets = false; | |
be0f161e | 154 | bool ets_zero_bw = false; |
08fb1dac SM |
155 | int strict_group; |
156 | int i; | |
157 | ||
be0f161e HN |
158 | for (i = 0; i <= max_tc; i++) { |
159 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { | |
08fb1dac | 160 | any_tc_mapped_to_ets = true; |
be0f161e HN |
161 | if (!ets->tc_tx_bw[i]) |
162 | ets_zero_bw = true; | |
163 | } | |
164 | } | |
08fb1dac | 165 | |
be0f161e HN |
166 | /* strict group has higher priority than ets group */ |
167 | strict_group = MLX5E_LOWEST_PRIO_GROUP; | |
168 | if (any_tc_mapped_to_ets) | |
169 | strict_group++; | |
170 | if (ets_zero_bw) | |
171 | strict_group++; | |
08fb1dac SM |
172 | |
173 | for (i = 0; i <= max_tc; i++) { | |
174 | switch (ets->tc_tsa[i]) { | |
175 | case IEEE_8021QAZ_TSA_VENDOR: | |
176 | tc_group[i] = MLX5E_VENDOR_TC_GROUP_NUM; | |
177 | break; | |
178 | case IEEE_8021QAZ_TSA_STRICT: | |
179 | tc_group[i] = strict_group++; | |
180 | break; | |
181 | case IEEE_8021QAZ_TSA_ETS: | |
be0f161e HN |
182 | tc_group[i] = MLX5E_LOWEST_PRIO_GROUP; |
183 | if (ets->tc_tx_bw[i] && ets_zero_bw) | |
184 | tc_group[i] = MLX5E_LOWEST_PRIO_GROUP + 1; | |
08fb1dac SM |
185 | break; |
186 | } | |
187 | } | |
188 | } | |
189 | ||
190 | static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw, | |
191 | u8 *tc_group, int max_tc) | |
192 | { | |
be0f161e HN |
193 | int bw_for_ets_zero_bw_tc = 0; |
194 | int last_ets_zero_bw_tc = -1; | |
195 | int num_ets_zero_bw = 0; | |
08fb1dac SM |
196 | int i; |
197 | ||
be0f161e HN |
198 | for (i = 0; i <= max_tc; i++) { |
199 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS && | |
200 | !ets->tc_tx_bw[i]) { | |
201 | num_ets_zero_bw++; | |
202 | last_ets_zero_bw_tc = i; | |
203 | } | |
204 | } | |
205 | ||
206 | if (num_ets_zero_bw) | |
207 | bw_for_ets_zero_bw_tc = MLX5E_MAX_BW_ALLOC / num_ets_zero_bw; | |
208 | ||
08fb1dac SM |
209 | for (i = 0; i <= max_tc; i++) { |
210 | switch (ets->tc_tsa[i]) { | |
211 | case IEEE_8021QAZ_TSA_VENDOR: | |
212 | tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; | |
213 | break; | |
214 | case IEEE_8021QAZ_TSA_STRICT: | |
215 | tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; | |
216 | break; | |
217 | case IEEE_8021QAZ_TSA_ETS: | |
be0f161e HN |
218 | tc_tx_bw[i] = ets->tc_tx_bw[i] ? |
219 | ets->tc_tx_bw[i] : | |
220 | bw_for_ets_zero_bw_tc; | |
08fb1dac SM |
221 | break; |
222 | } | |
223 | } | |
be0f161e HN |
224 | |
225 | /* Make sure the total bw for ets zero bw group is 100% */ | |
226 | if (last_ets_zero_bw_tc != -1) | |
227 | tc_tx_bw[last_ets_zero_bw_tc] += | |
228 | MLX5E_MAX_BW_ALLOC % num_ets_zero_bw; | |
08fb1dac SM |
229 | } |
230 | ||
be0f161e HN |
231 | /* If there are ETS BW 0, |
232 | * Set ETS group # to 1 for all ETS non zero BW tcs. Their sum must be 100%. | |
233 | * Set group #0 to all the ETS BW 0 tcs and | |
234 | * equally splits the 100% BW between them | |
235 | * Report both group #0 and #1 as ETS type. | |
236 | * All the tcs in group #0 will be reported with 0% BW. | |
237 | */ | |
08fb1dac SM |
238 | int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets) |
239 | { | |
240 | struct mlx5_core_dev *mdev = priv->mdev; | |
241 | u8 tc_tx_bw[IEEE_8021QAZ_MAX_TCS]; | |
242 | u8 tc_group[IEEE_8021QAZ_MAX_TCS]; | |
243 | int max_tc = mlx5_max_tc(mdev); | |
5da8bc3e | 244 | int err, i; |
08fb1dac | 245 | |
08fb1dac SM |
246 | mlx5e_build_tc_group(ets, tc_group, max_tc); |
247 | mlx5e_build_tc_tx_bw(ets, tc_tx_bw, tc_group, max_tc); | |
248 | ||
249 | err = mlx5_set_port_prio_tc(mdev, ets->prio_tc); | |
250 | if (err) | |
251 | return err; | |
252 | ||
253 | err = mlx5_set_port_tc_group(mdev, tc_group); | |
254 | if (err) | |
255 | return err; | |
256 | ||
820c2c5e HN |
257 | err = mlx5_set_port_tc_bw_alloc(mdev, tc_tx_bw); |
258 | ||
259 | if (err) | |
260 | return err; | |
261 | ||
262 | memcpy(priv->dcbx.tc_tsa, ets->tc_tsa, sizeof(ets->tc_tsa)); | |
5da8bc3e IK |
263 | |
264 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | |
265 | mlx5e_dbg(HW, priv, "%s: prio_%d <=> tc_%d\n", | |
266 | __func__, i, ets->prio_tc[i]); | |
267 | mlx5e_dbg(HW, priv, "%s: tc_%d <=> tx_bw_%d%%, group_%d\n", | |
268 | __func__, i, tc_tx_bw[i], tc_group[i]); | |
269 | } | |
270 | ||
820c2c5e | 271 | return err; |
08fb1dac SM |
272 | } |
273 | ||
1722b969 EBE |
274 | static int mlx5e_dbcnl_validate_ets(struct net_device *netdev, |
275 | struct ieee_ets *ets) | |
08fb1dac SM |
276 | { |
277 | int bw_sum = 0; | |
278 | int i; | |
279 | ||
280 | /* Validate Priority */ | |
281 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | |
1722b969 EBE |
282 | if (ets->prio_tc[i] >= MLX5E_MAX_PRIORITY) { |
283 | netdev_err(netdev, | |
284 | "Failed to validate ETS: priority value greater than max(%d)\n", | |
285 | MLX5E_MAX_PRIORITY); | |
08fb1dac | 286 | return -EINVAL; |
1722b969 | 287 | } |
08fb1dac SM |
288 | } |
289 | ||
290 | /* Validate Bandwidth Sum */ | |
be0f161e HN |
291 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) |
292 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) | |
08fb1dac | 293 | bw_sum += ets->tc_tx_bw[i]; |
08fb1dac | 294 | |
1722b969 EBE |
295 | if (bw_sum != 0 && bw_sum != 100) { |
296 | netdev_err(netdev, | |
297 | "Failed to validate ETS: BW sum is illegal\n"); | |
08fb1dac | 298 | return -EINVAL; |
1722b969 | 299 | } |
08fb1dac SM |
300 | return 0; |
301 | } | |
302 | ||
303 | static int mlx5e_dcbnl_ieee_setets(struct net_device *netdev, | |
304 | struct ieee_ets *ets) | |
305 | { | |
306 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
307 | int err; | |
308 | ||
820c2c5e | 309 | if (!MLX5_CAP_GEN(priv->mdev, ets)) |
9eb78923 | 310 | return -EOPNOTSUPP; |
820c2c5e | 311 | |
1722b969 | 312 | err = mlx5e_dbcnl_validate_ets(netdev, ets); |
08fb1dac SM |
313 | if (err) |
314 | return err; | |
315 | ||
316 | err = mlx5e_dcbnl_ieee_setets_core(priv, ets); | |
317 | if (err) | |
318 | return err; | |
319 | ||
08fb1dac SM |
320 | return 0; |
321 | } | |
322 | ||
ef918433 AS |
323 | static int mlx5e_dcbnl_ieee_getpfc(struct net_device *dev, |
324 | struct ieee_pfc *pfc) | |
325 | { | |
326 | struct mlx5e_priv *priv = netdev_priv(dev); | |
327 | struct mlx5_core_dev *mdev = priv->mdev; | |
cf678570 GP |
328 | struct mlx5e_pport_stats *pstats = &priv->stats.pport; |
329 | int i; | |
ef918433 AS |
330 | |
331 | pfc->pfc_cap = mlx5_max_tc(mdev) + 1; | |
cf678570 GP |
332 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { |
333 | pfc->requests[i] = PPORT_PER_PRIO_GET(pstats, i, tx_pause); | |
334 | pfc->indications[i] = PPORT_PER_PRIO_GET(pstats, i, rx_pause); | |
335 | } | |
ef918433 AS |
336 | |
337 | return mlx5_query_port_pfc(mdev, &pfc->pfc_en, NULL); | |
338 | } | |
339 | ||
340 | static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, | |
341 | struct ieee_pfc *pfc) | |
342 | { | |
343 | struct mlx5e_priv *priv = netdev_priv(dev); | |
344 | struct mlx5_core_dev *mdev = priv->mdev; | |
ef918433 AS |
345 | u8 curr_pfc_en; |
346 | int ret; | |
347 | ||
348 | mlx5_query_port_pfc(mdev, &curr_pfc_en, NULL); | |
349 | ||
350 | if (pfc->pfc_en == curr_pfc_en) | |
351 | return 0; | |
352 | ||
ef918433 | 353 | ret = mlx5_set_port_pfc(mdev, pfc->pfc_en, pfc->pfc_en); |
667daeda | 354 | mlx5_toggle_port_link(mdev); |
ef918433 | 355 | |
5da8bc3e IK |
356 | if (!ret) { |
357 | mlx5e_dbg(HW, priv, | |
358 | "%s: PFC per priority bit mask: 0x%x\n", | |
359 | __func__, pfc->pfc_en); | |
360 | } | |
ef918433 AS |
361 | return ret; |
362 | } | |
363 | ||
08fb1dac SM |
364 | static u8 mlx5e_dcbnl_getdcbx(struct net_device *dev) |
365 | { | |
0eca995f | 366 | struct mlx5e_priv *priv = netdev_priv(dev); |
0eca995f | 367 | |
9e10bf1d | 368 | return priv->dcbx.cap; |
08fb1dac SM |
369 | } |
370 | ||
371 | static u8 mlx5e_dcbnl_setdcbx(struct net_device *dev, u8 mode) | |
372 | { | |
0eca995f HN |
373 | struct mlx5e_priv *priv = netdev_priv(dev); |
374 | struct mlx5e_dcbx *dcbx = &priv->dcbx; | |
375 | ||
33e21c59 HN |
376 | if (mode & DCB_CAP_DCBX_LLD_MANAGED) |
377 | return 1; | |
378 | ||
0eca995f HN |
379 | if ((!mode) && MLX5_CAP_GEN(priv->mdev, dcbx)) { |
380 | if (dcbx->mode == MLX5E_DCBX_PARAM_VER_OPER_AUTO) | |
381 | return 0; | |
382 | ||
383 | /* set dcbx to fw controlled */ | |
384 | if (!mlx5e_dcbnl_set_dcbx_mode(priv, MLX5E_DCBX_PARAM_VER_OPER_AUTO)) { | |
385 | dcbx->mode = MLX5E_DCBX_PARAM_VER_OPER_AUTO; | |
9e10bf1d | 386 | dcbx->cap &= ~DCB_CAP_DCBX_HOST; |
0eca995f HN |
387 | return 0; |
388 | } | |
389 | ||
390 | return 1; | |
391 | } | |
392 | ||
33e21c59 | 393 | if (!(mode & DCB_CAP_DCBX_HOST)) |
e207b7e9 HN |
394 | return 1; |
395 | ||
33e21c59 | 396 | if (mlx5e_dcbnl_switch_to_host_mode(netdev_priv(dev))) |
08fb1dac SM |
397 | return 1; |
398 | ||
9e10bf1d HN |
399 | dcbx->cap = mode; |
400 | ||
08fb1dac SM |
401 | return 0; |
402 | } | |
403 | ||
2a5e7a13 HN |
404 | static int mlx5e_dcbnl_ieee_setapp(struct net_device *dev, struct dcb_app *app) |
405 | { | |
406 | struct mlx5e_priv *priv = netdev_priv(dev); | |
407 | struct dcb_app temp; | |
408 | bool is_new; | |
409 | int err; | |
410 | ||
411 | if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP) | |
412 | return -EINVAL; | |
413 | ||
414 | if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager)) | |
415 | return -EINVAL; | |
416 | ||
417 | if (!MLX5_DSCP_SUPPORTED(priv->mdev)) | |
418 | return -EINVAL; | |
419 | ||
420 | if (app->protocol >= MLX5E_MAX_DSCP) | |
421 | return -EINVAL; | |
422 | ||
423 | /* Save the old entry info */ | |
424 | temp.selector = IEEE_8021QAZ_APP_SEL_DSCP; | |
425 | temp.protocol = app->protocol; | |
426 | temp.priority = priv->dcbx_dp.dscp2prio[app->protocol]; | |
427 | ||
428 | /* Check if need to switch to dscp trust state */ | |
429 | if (!priv->dcbx.dscp_app_cnt) { | |
430 | err = mlx5e_set_trust_state(priv, MLX5_QPTS_TRUST_DSCP); | |
431 | if (err) | |
432 | return err; | |
433 | } | |
434 | ||
435 | /* Skip the fw command if new and old mapping are the same */ | |
436 | if (app->priority != priv->dcbx_dp.dscp2prio[app->protocol]) { | |
437 | err = mlx5e_set_dscp2prio(priv, app->protocol, app->priority); | |
438 | if (err) | |
439 | goto fw_err; | |
440 | } | |
441 | ||
442 | /* Delete the old entry if exists */ | |
443 | is_new = false; | |
444 | err = dcb_ieee_delapp(dev, &temp); | |
445 | if (err) | |
446 | is_new = true; | |
447 | ||
448 | /* Add new entry and update counter */ | |
449 | err = dcb_ieee_setapp(dev, app); | |
450 | if (err) | |
451 | return err; | |
452 | ||
453 | if (is_new) | |
454 | priv->dcbx.dscp_app_cnt++; | |
455 | ||
456 | return err; | |
457 | ||
458 | fw_err: | |
459 | mlx5e_set_trust_state(priv, MLX5_QPTS_TRUST_PCP); | |
460 | return err; | |
461 | } | |
462 | ||
463 | static int mlx5e_dcbnl_ieee_delapp(struct net_device *dev, struct dcb_app *app) | |
464 | { | |
465 | struct mlx5e_priv *priv = netdev_priv(dev); | |
466 | int err; | |
467 | ||
468 | if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP) | |
469 | return -EINVAL; | |
470 | ||
471 | if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager)) | |
472 | return -EINVAL; | |
473 | ||
474 | if (!MLX5_DSCP_SUPPORTED(priv->mdev)) | |
475 | return -EINVAL; | |
476 | ||
477 | if (app->protocol >= MLX5E_MAX_DSCP) | |
478 | return -EINVAL; | |
479 | ||
480 | /* Skip if no dscp app entry */ | |
481 | if (!priv->dcbx.dscp_app_cnt) | |
482 | return -ENOENT; | |
483 | ||
484 | /* Check if the entry matches fw setting */ | |
485 | if (app->priority != priv->dcbx_dp.dscp2prio[app->protocol]) | |
486 | return -ENOENT; | |
487 | ||
488 | /* Delete the app entry */ | |
489 | err = dcb_ieee_delapp(dev, app); | |
490 | if (err) | |
491 | return err; | |
492 | ||
493 | /* Reset the priority mapping back to zero */ | |
494 | err = mlx5e_set_dscp2prio(priv, app->protocol, 0); | |
495 | if (err) | |
496 | goto fw_err; | |
497 | ||
498 | priv->dcbx.dscp_app_cnt--; | |
499 | ||
500 | /* Check if need to switch to pcp trust state */ | |
501 | if (!priv->dcbx.dscp_app_cnt) | |
502 | err = mlx5e_set_trust_state(priv, MLX5_QPTS_TRUST_PCP); | |
503 | ||
504 | return err; | |
505 | ||
506 | fw_err: | |
507 | mlx5e_set_trust_state(priv, MLX5_QPTS_TRUST_PCP); | |
508 | return err; | |
509 | } | |
510 | ||
d8880795 TT |
511 | static int mlx5e_dcbnl_ieee_getmaxrate(struct net_device *netdev, |
512 | struct ieee_maxrate *maxrate) | |
513 | { | |
514 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
515 | struct mlx5_core_dev *mdev = priv->mdev; | |
516 | u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; | |
517 | u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; | |
518 | int err; | |
519 | int i; | |
520 | ||
521 | err = mlx5_query_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit); | |
522 | if (err) | |
523 | return err; | |
524 | ||
525 | memset(maxrate->tc_maxrate, 0, sizeof(maxrate->tc_maxrate)); | |
526 | ||
527 | for (i = 0; i <= mlx5_max_tc(mdev); i++) { | |
528 | switch (max_bw_unit[i]) { | |
529 | case MLX5_100_MBPS_UNIT: | |
530 | maxrate->tc_maxrate[i] = max_bw_value[i] * MLX5E_100MB; | |
531 | break; | |
532 | case MLX5_GBPS_UNIT: | |
533 | maxrate->tc_maxrate[i] = max_bw_value[i] * MLX5E_1GB; | |
534 | break; | |
535 | case MLX5_BW_NO_LIMIT: | |
536 | break; | |
537 | default: | |
538 | WARN(true, "non-supported BW unit"); | |
539 | break; | |
540 | } | |
541 | } | |
542 | ||
543 | return 0; | |
544 | } | |
545 | ||
546 | static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev, | |
547 | struct ieee_maxrate *maxrate) | |
548 | { | |
549 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
550 | struct mlx5_core_dev *mdev = priv->mdev; | |
551 | u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; | |
552 | u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; | |
553 | __u64 upper_limit_mbps = roundup(255 * MLX5E_100MB, MLX5E_1GB); | |
554 | int i; | |
555 | ||
556 | memset(max_bw_value, 0, sizeof(max_bw_value)); | |
557 | memset(max_bw_unit, 0, sizeof(max_bw_unit)); | |
558 | ||
559 | for (i = 0; i <= mlx5_max_tc(mdev); i++) { | |
560 | if (!maxrate->tc_maxrate[i]) { | |
561 | max_bw_unit[i] = MLX5_BW_NO_LIMIT; | |
562 | continue; | |
563 | } | |
564 | if (maxrate->tc_maxrate[i] < upper_limit_mbps) { | |
565 | max_bw_value[i] = div_u64(maxrate->tc_maxrate[i], | |
566 | MLX5E_100MB); | |
567 | max_bw_value[i] = max_bw_value[i] ? max_bw_value[i] : 1; | |
568 | max_bw_unit[i] = MLX5_100_MBPS_UNIT; | |
569 | } else { | |
570 | max_bw_value[i] = div_u64(maxrate->tc_maxrate[i], | |
571 | MLX5E_1GB); | |
572 | max_bw_unit[i] = MLX5_GBPS_UNIT; | |
573 | } | |
574 | } | |
575 | ||
5da8bc3e IK |
576 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { |
577 | mlx5e_dbg(HW, priv, "%s: tc_%d <=> max_bw %d Gbps\n", | |
578 | __func__, i, max_bw_value[i]); | |
579 | } | |
580 | ||
d8880795 TT |
581 | return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit); |
582 | } | |
583 | ||
3a6a931d HN |
584 | static u8 mlx5e_dcbnl_setall(struct net_device *netdev) |
585 | { | |
586 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
587 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
588 | struct mlx5_core_dev *mdev = priv->mdev; | |
589 | struct ieee_ets ets; | |
590 | struct ieee_pfc pfc; | |
9eb78923 | 591 | int err = -EOPNOTSUPP; |
3a6a931d HN |
592 | int i; |
593 | ||
820c2c5e HN |
594 | if (!MLX5_CAP_GEN(mdev, ets)) |
595 | goto out; | |
596 | ||
3a6a931d HN |
597 | memset(&ets, 0, sizeof(ets)); |
598 | memset(&pfc, 0, sizeof(pfc)); | |
599 | ||
600 | ets.ets_cap = IEEE_8021QAZ_MAX_TCS; | |
601 | for (i = 0; i < CEE_DCBX_MAX_PGS; i++) { | |
602 | ets.tc_tx_bw[i] = cee_cfg->pg_bw_pct[i]; | |
603 | ets.tc_rx_bw[i] = cee_cfg->pg_bw_pct[i]; | |
604 | ets.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; | |
605 | ets.prio_tc[i] = cee_cfg->prio_to_pg_map[i]; | |
5da8bc3e IK |
606 | mlx5e_dbg(HW, priv, |
607 | "%s: Priority group %d: tx_bw %d, rx_bw %d, prio_tc %d\n", | |
608 | __func__, i, ets.tc_tx_bw[i], ets.tc_rx_bw[i], | |
609 | ets.prio_tc[i]); | |
3a6a931d HN |
610 | } |
611 | ||
612 | err = mlx5e_dbcnl_validate_ets(netdev, &ets); | |
613 | if (err) { | |
614 | netdev_err(netdev, | |
615 | "%s, Failed to validate ETS: %d\n", __func__, err); | |
616 | goto out; | |
617 | } | |
618 | ||
619 | err = mlx5e_dcbnl_ieee_setets_core(priv, &ets); | |
620 | if (err) { | |
621 | netdev_err(netdev, | |
622 | "%s, Failed to set ETS: %d\n", __func__, err); | |
623 | goto out; | |
624 | } | |
625 | ||
626 | /* Set PFC */ | |
627 | pfc.pfc_cap = mlx5_max_tc(mdev) + 1; | |
628 | if (!cee_cfg->pfc_enable) | |
629 | pfc.pfc_en = 0; | |
630 | else | |
631 | for (i = 0; i < CEE_DCBX_MAX_PRIO; i++) | |
632 | pfc.pfc_en |= cee_cfg->pfc_setting[i] << i; | |
633 | ||
634 | err = mlx5e_dcbnl_ieee_setpfc(netdev, &pfc); | |
635 | if (err) { | |
636 | netdev_err(netdev, | |
637 | "%s, Failed to set PFC: %d\n", __func__, err); | |
638 | goto out; | |
639 | } | |
640 | out: | |
641 | return err ? MLX5_DCB_NO_CHG : MLX5_DCB_CHG_RESET; | |
642 | } | |
643 | ||
644 | static u8 mlx5e_dcbnl_getstate(struct net_device *netdev) | |
645 | { | |
646 | return MLX5E_CEE_STATE_UP; | |
647 | } | |
648 | ||
649 | static void mlx5e_dcbnl_getpermhwaddr(struct net_device *netdev, | |
650 | u8 *perm_addr) | |
651 | { | |
652 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
653 | ||
654 | if (!perm_addr) | |
655 | return; | |
656 | ||
d968f0f2 HN |
657 | memset(perm_addr, 0xff, MAX_ADDR_LEN); |
658 | ||
3a6a931d HN |
659 | mlx5_query_nic_vport_mac_address(priv->mdev, 0, perm_addr); |
660 | } | |
661 | ||
662 | static void mlx5e_dcbnl_setpgtccfgtx(struct net_device *netdev, | |
663 | int priority, u8 prio_type, | |
664 | u8 pgid, u8 bw_pct, u8 up_map) | |
665 | { | |
666 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
667 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
668 | ||
669 | if (priority >= CEE_DCBX_MAX_PRIO) { | |
670 | netdev_err(netdev, | |
671 | "%s, priority is out of range\n", __func__); | |
672 | return; | |
673 | } | |
674 | ||
675 | if (pgid >= CEE_DCBX_MAX_PGS) { | |
676 | netdev_err(netdev, | |
677 | "%s, priority group is out of range\n", __func__); | |
678 | return; | |
679 | } | |
680 | ||
681 | cee_cfg->prio_to_pg_map[priority] = pgid; | |
682 | } | |
683 | ||
684 | static void mlx5e_dcbnl_setpgbwgcfgtx(struct net_device *netdev, | |
685 | int pgid, u8 bw_pct) | |
686 | { | |
687 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
688 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
689 | ||
690 | if (pgid >= CEE_DCBX_MAX_PGS) { | |
691 | netdev_err(netdev, | |
692 | "%s, priority group is out of range\n", __func__); | |
693 | return; | |
694 | } | |
695 | ||
696 | cee_cfg->pg_bw_pct[pgid] = bw_pct; | |
697 | } | |
698 | ||
699 | static void mlx5e_dcbnl_getpgtccfgtx(struct net_device *netdev, | |
700 | int priority, u8 *prio_type, | |
701 | u8 *pgid, u8 *bw_pct, u8 *up_map) | |
702 | { | |
703 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
704 | struct mlx5_core_dev *mdev = priv->mdev; | |
705 | ||
d15118af MS |
706 | if (!MLX5_CAP_GEN(priv->mdev, ets)) { |
707 | netdev_err(netdev, "%s, ets is not supported\n", __func__); | |
708 | return; | |
709 | } | |
710 | ||
3a6a931d HN |
711 | if (priority >= CEE_DCBX_MAX_PRIO) { |
712 | netdev_err(netdev, | |
713 | "%s, priority is out of range\n", __func__); | |
714 | return; | |
715 | } | |
716 | ||
717 | *prio_type = 0; | |
718 | *bw_pct = 0; | |
719 | *up_map = 0; | |
720 | ||
721 | if (mlx5_query_port_prio_tc(mdev, priority, pgid)) | |
722 | *pgid = 0; | |
723 | } | |
724 | ||
725 | static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev, | |
726 | int pgid, u8 *bw_pct) | |
727 | { | |
be0f161e | 728 | struct ieee_ets ets; |
3a6a931d HN |
729 | |
730 | if (pgid >= CEE_DCBX_MAX_PGS) { | |
731 | netdev_err(netdev, | |
732 | "%s, priority group is out of range\n", __func__); | |
733 | return; | |
734 | } | |
735 | ||
be0f161e HN |
736 | mlx5e_dcbnl_ieee_getets(netdev, &ets); |
737 | *bw_pct = ets.tc_tx_bw[pgid]; | |
3a6a931d HN |
738 | } |
739 | ||
740 | static void mlx5e_dcbnl_setpfccfg(struct net_device *netdev, | |
741 | int priority, u8 setting) | |
742 | { | |
743 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
744 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
745 | ||
746 | if (priority >= CEE_DCBX_MAX_PRIO) { | |
747 | netdev_err(netdev, | |
748 | "%s, priority is out of range\n", __func__); | |
749 | return; | |
750 | } | |
751 | ||
752 | if (setting > 1) | |
753 | return; | |
754 | ||
755 | cee_cfg->pfc_setting[priority] = setting; | |
756 | } | |
757 | ||
758 | static int | |
759 | mlx5e_dcbnl_get_priority_pfc(struct net_device *netdev, | |
760 | int priority, u8 *setting) | |
761 | { | |
762 | struct ieee_pfc pfc; | |
763 | int err; | |
764 | ||
765 | err = mlx5e_dcbnl_ieee_getpfc(netdev, &pfc); | |
766 | ||
767 | if (err) | |
768 | *setting = 0; | |
769 | else | |
770 | *setting = (pfc.pfc_en >> priority) & 0x01; | |
771 | ||
772 | return err; | |
773 | } | |
774 | ||
775 | static void mlx5e_dcbnl_getpfccfg(struct net_device *netdev, | |
776 | int priority, u8 *setting) | |
777 | { | |
778 | if (priority >= CEE_DCBX_MAX_PRIO) { | |
779 | netdev_err(netdev, | |
780 | "%s, priority is out of range\n", __func__); | |
781 | return; | |
782 | } | |
783 | ||
784 | if (!setting) | |
785 | return; | |
786 | ||
787 | mlx5e_dcbnl_get_priority_pfc(netdev, priority, setting); | |
788 | } | |
789 | ||
790 | static u8 mlx5e_dcbnl_getcap(struct net_device *netdev, | |
791 | int capid, u8 *cap) | |
792 | { | |
793 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
794 | struct mlx5_core_dev *mdev = priv->mdev; | |
795 | u8 rval = 0; | |
796 | ||
797 | switch (capid) { | |
798 | case DCB_CAP_ATTR_PG: | |
799 | *cap = true; | |
800 | break; | |
801 | case DCB_CAP_ATTR_PFC: | |
802 | *cap = true; | |
803 | break; | |
804 | case DCB_CAP_ATTR_UP2TC: | |
805 | *cap = false; | |
806 | break; | |
807 | case DCB_CAP_ATTR_PG_TCS: | |
808 | *cap = 1 << mlx5_max_tc(mdev); | |
809 | break; | |
810 | case DCB_CAP_ATTR_PFC_TCS: | |
811 | *cap = 1 << mlx5_max_tc(mdev); | |
812 | break; | |
813 | case DCB_CAP_ATTR_GSP: | |
814 | *cap = false; | |
815 | break; | |
816 | case DCB_CAP_ATTR_BCN: | |
817 | *cap = false; | |
818 | break; | |
819 | case DCB_CAP_ATTR_DCBX: | |
9e10bf1d HN |
820 | *cap = priv->dcbx.cap | |
821 | DCB_CAP_DCBX_VER_CEE | | |
822 | DCB_CAP_DCBX_VER_IEEE; | |
3a6a931d HN |
823 | break; |
824 | default: | |
825 | *cap = 0; | |
826 | rval = 1; | |
827 | break; | |
828 | } | |
829 | ||
830 | return rval; | |
831 | } | |
832 | ||
833 | static int mlx5e_dcbnl_getnumtcs(struct net_device *netdev, | |
834 | int tcs_id, u8 *num) | |
835 | { | |
836 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
837 | struct mlx5_core_dev *mdev = priv->mdev; | |
838 | ||
839 | switch (tcs_id) { | |
840 | case DCB_NUMTCS_ATTR_PG: | |
841 | case DCB_NUMTCS_ATTR_PFC: | |
842 | *num = mlx5_max_tc(mdev) + 1; | |
843 | break; | |
844 | default: | |
845 | return -EINVAL; | |
846 | } | |
847 | ||
848 | return 0; | |
849 | } | |
850 | ||
851 | static u8 mlx5e_dcbnl_getpfcstate(struct net_device *netdev) | |
852 | { | |
853 | struct ieee_pfc pfc; | |
854 | ||
855 | if (mlx5e_dcbnl_ieee_getpfc(netdev, &pfc)) | |
856 | return MLX5E_CEE_STATE_DOWN; | |
857 | ||
858 | return pfc.pfc_en ? MLX5E_CEE_STATE_UP : MLX5E_CEE_STATE_DOWN; | |
859 | } | |
860 | ||
861 | static void mlx5e_dcbnl_setpfcstate(struct net_device *netdev, u8 state) | |
862 | { | |
863 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
864 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
865 | ||
866 | if ((state != MLX5E_CEE_STATE_UP) && (state != MLX5E_CEE_STATE_DOWN)) | |
867 | return; | |
868 | ||
869 | cee_cfg->pfc_enable = state; | |
870 | } | |
871 | ||
08fb1dac SM |
872 | const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = { |
873 | .ieee_getets = mlx5e_dcbnl_ieee_getets, | |
874 | .ieee_setets = mlx5e_dcbnl_ieee_setets, | |
d8880795 TT |
875 | .ieee_getmaxrate = mlx5e_dcbnl_ieee_getmaxrate, |
876 | .ieee_setmaxrate = mlx5e_dcbnl_ieee_setmaxrate, | |
ef918433 AS |
877 | .ieee_getpfc = mlx5e_dcbnl_ieee_getpfc, |
878 | .ieee_setpfc = mlx5e_dcbnl_ieee_setpfc, | |
2a5e7a13 HN |
879 | .ieee_setapp = mlx5e_dcbnl_ieee_setapp, |
880 | .ieee_delapp = mlx5e_dcbnl_ieee_delapp, | |
08fb1dac SM |
881 | .getdcbx = mlx5e_dcbnl_getdcbx, |
882 | .setdcbx = mlx5e_dcbnl_setdcbx, | |
3a6a931d HN |
883 | |
884 | /* CEE interfaces */ | |
885 | .setall = mlx5e_dcbnl_setall, | |
886 | .getstate = mlx5e_dcbnl_getstate, | |
887 | .getpermhwaddr = mlx5e_dcbnl_getpermhwaddr, | |
888 | ||
889 | .setpgtccfgtx = mlx5e_dcbnl_setpgtccfgtx, | |
890 | .setpgbwgcfgtx = mlx5e_dcbnl_setpgbwgcfgtx, | |
891 | .getpgtccfgtx = mlx5e_dcbnl_getpgtccfgtx, | |
892 | .getpgbwgcfgtx = mlx5e_dcbnl_getpgbwgcfgtx, | |
893 | ||
894 | .setpfccfg = mlx5e_dcbnl_setpfccfg, | |
895 | .getpfccfg = mlx5e_dcbnl_getpfccfg, | |
896 | .getcap = mlx5e_dcbnl_getcap, | |
897 | .getnumtcs = mlx5e_dcbnl_getnumtcs, | |
898 | .getpfcstate = mlx5e_dcbnl_getpfcstate, | |
899 | .setpfcstate = mlx5e_dcbnl_setpfcstate, | |
08fb1dac | 900 | }; |
e207b7e9 HN |
901 | |
902 | static void mlx5e_dcbnl_query_dcbx_mode(struct mlx5e_priv *priv, | |
903 | enum mlx5_dcbx_oper_mode *mode) | |
904 | { | |
905 | u32 out[MLX5_ST_SZ_DW(dcbx_param)]; | |
906 | ||
907 | *mode = MLX5E_DCBX_PARAM_VER_OPER_HOST; | |
908 | ||
909 | if (!mlx5_query_port_dcbx_param(priv->mdev, out)) | |
910 | *mode = MLX5_GET(dcbx_param, out, version_oper); | |
911 | ||
912 | /* From driver's point of view, we only care if the mode | |
913 | * is host (HOST) or non-host (AUTO) | |
914 | */ | |
915 | if (*mode != MLX5E_DCBX_PARAM_VER_OPER_HOST) | |
916 | *mode = MLX5E_DCBX_PARAM_VER_OPER_AUTO; | |
917 | } | |
918 | ||
919 | static void mlx5e_ets_init(struct mlx5e_priv *priv) | |
920 | { | |
921 | int i; | |
922 | struct ieee_ets ets; | |
923 | ||
4525a45b HN |
924 | if (!MLX5_CAP_GEN(priv->mdev, ets)) |
925 | return; | |
926 | ||
e207b7e9 HN |
927 | memset(&ets, 0, sizeof(ets)); |
928 | ets.ets_cap = mlx5_max_tc(priv->mdev) + 1; | |
929 | for (i = 0; i < ets.ets_cap; i++) { | |
930 | ets.tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; | |
931 | ets.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR; | |
932 | ets.prio_tc[i] = i; | |
933 | } | |
934 | ||
e207b7e9 HN |
935 | /* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */ |
936 | ets.prio_tc[0] = 1; | |
937 | ets.prio_tc[1] = 0; | |
938 | ||
939 | mlx5e_dcbnl_ieee_setets_core(priv, &ets); | |
940 | } | |
941 | ||
2a5e7a13 HN |
942 | enum { |
943 | INIT, | |
944 | DELETE, | |
945 | }; | |
946 | ||
947 | static void mlx5e_dcbnl_dscp_app(struct mlx5e_priv *priv, int action) | |
948 | { | |
949 | struct dcb_app temp; | |
950 | int i; | |
951 | ||
952 | if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager)) | |
953 | return; | |
954 | ||
955 | if (!MLX5_DSCP_SUPPORTED(priv->mdev)) | |
956 | return; | |
957 | ||
958 | /* No SEL_DSCP entry in non DSCP state */ | |
959 | if (priv->dcbx_dp.trust_state != MLX5_QPTS_TRUST_DSCP) | |
960 | return; | |
961 | ||
962 | temp.selector = IEEE_8021QAZ_APP_SEL_DSCP; | |
963 | for (i = 0; i < MLX5E_MAX_DSCP; i++) { | |
964 | temp.protocol = i; | |
965 | temp.priority = priv->dcbx_dp.dscp2prio[i]; | |
966 | if (action == INIT) | |
967 | dcb_ieee_setapp(priv->netdev, &temp); | |
968 | else | |
969 | dcb_ieee_delapp(priv->netdev, &temp); | |
970 | } | |
971 | ||
972 | priv->dcbx.dscp_app_cnt = (action == INIT) ? MLX5E_MAX_DSCP : 0; | |
973 | } | |
974 | ||
975 | void mlx5e_dcbnl_init_app(struct mlx5e_priv *priv) | |
976 | { | |
977 | mlx5e_dcbnl_dscp_app(priv, INIT); | |
978 | } | |
979 | ||
980 | void mlx5e_dcbnl_delete_app(struct mlx5e_priv *priv) | |
981 | { | |
982 | mlx5e_dcbnl_dscp_app(priv, DELETE); | |
983 | } | |
984 | ||
fbcb127e HN |
985 | static void mlx5e_trust_update_tx_min_inline_mode(struct mlx5e_priv *priv, |
986 | struct mlx5e_params *params) | |
987 | { | |
988 | params->tx_min_inline_mode = mlx5e_params_calculate_tx_min_inline(priv->mdev); | |
989 | if (priv->dcbx_dp.trust_state == MLX5_QPTS_TRUST_DSCP && | |
990 | params->tx_min_inline_mode == MLX5_INLINE_MODE_L2) | |
991 | params->tx_min_inline_mode = MLX5_INLINE_MODE_IP; | |
992 | } | |
993 | ||
994 | static void mlx5e_trust_update_sq_inline_mode(struct mlx5e_priv *priv) | |
995 | { | |
996 | struct mlx5e_channels new_channels = {}; | |
997 | ||
998 | mutex_lock(&priv->state_lock); | |
999 | ||
1000 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) | |
1001 | goto out; | |
1002 | ||
1003 | new_channels.params = priv->channels.params; | |
1004 | mlx5e_trust_update_tx_min_inline_mode(priv, &new_channels.params); | |
1005 | ||
1006 | /* Skip if tx_min_inline is the same */ | |
1007 | if (new_channels.params.tx_min_inline_mode == | |
1008 | priv->channels.params.tx_min_inline_mode) | |
1009 | goto out; | |
1010 | ||
1011 | if (mlx5e_open_channels(priv, &new_channels)) | |
1012 | goto out; | |
1013 | mlx5e_switch_priv_channels(priv, &new_channels, NULL); | |
1014 | ||
1015 | out: | |
1016 | mutex_unlock(&priv->state_lock); | |
1017 | } | |
1018 | ||
2a5e7a13 HN |
1019 | static int mlx5e_set_trust_state(struct mlx5e_priv *priv, u8 trust_state) |
1020 | { | |
1021 | int err; | |
1022 | ||
1023 | err = mlx5_set_trust_state(priv->mdev, trust_state); | |
1024 | if (err) | |
1025 | return err; | |
1026 | priv->dcbx_dp.trust_state = trust_state; | |
fbcb127e | 1027 | mlx5e_trust_update_sq_inline_mode(priv); |
2a5e7a13 HN |
1028 | |
1029 | return err; | |
1030 | } | |
1031 | ||
1032 | static int mlx5e_set_dscp2prio(struct mlx5e_priv *priv, u8 dscp, u8 prio) | |
1033 | { | |
1034 | int err; | |
1035 | ||
1036 | err = mlx5_set_dscp2prio(priv->mdev, dscp, prio); | |
1037 | if (err) | |
1038 | return err; | |
1039 | ||
1040 | priv->dcbx_dp.dscp2prio[dscp] = prio; | |
1041 | return err; | |
1042 | } | |
1043 | ||
1044 | static int mlx5e_trust_initialize(struct mlx5e_priv *priv) | |
1045 | { | |
1046 | struct mlx5_core_dev *mdev = priv->mdev; | |
1047 | int err; | |
1048 | ||
1049 | if (!MLX5_DSCP_SUPPORTED(mdev)) | |
1050 | return 0; | |
1051 | ||
1052 | err = mlx5_query_trust_state(priv->mdev, &priv->dcbx_dp.trust_state); | |
1053 | if (err) | |
1054 | return err; | |
1055 | ||
fbcb127e HN |
1056 | mlx5e_trust_update_tx_min_inline_mode(priv, &priv->channels.params); |
1057 | ||
2a5e7a13 HN |
1058 | err = mlx5_query_dscp2prio(priv->mdev, priv->dcbx_dp.dscp2prio); |
1059 | if (err) | |
1060 | return err; | |
1061 | ||
1062 | return 0; | |
1063 | } | |
1064 | ||
e207b7e9 HN |
1065 | void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv) |
1066 | { | |
1067 | struct mlx5e_dcbx *dcbx = &priv->dcbx; | |
1068 | ||
2a5e7a13 HN |
1069 | mlx5e_trust_initialize(priv); |
1070 | ||
33c52b67 HN |
1071 | if (!MLX5_CAP_GEN(priv->mdev, qos)) |
1072 | return; | |
1073 | ||
e207b7e9 HN |
1074 | if (MLX5_CAP_GEN(priv->mdev, dcbx)) |
1075 | mlx5e_dcbnl_query_dcbx_mode(priv, &dcbx->mode); | |
1076 | ||
9e10bf1d HN |
1077 | priv->dcbx.cap = DCB_CAP_DCBX_VER_CEE | |
1078 | DCB_CAP_DCBX_VER_IEEE; | |
1079 | if (priv->dcbx.mode == MLX5E_DCBX_PARAM_VER_OPER_HOST) | |
1080 | priv->dcbx.cap |= DCB_CAP_DCBX_HOST; | |
1081 | ||
e207b7e9 HN |
1082 | mlx5e_ets_init(priv); |
1083 | } |