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 | ||
08fb1dac SM |
44 | static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev, |
45 | struct ieee_ets *ets) | |
46 | { | |
47 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
48 | ||
49 | if (!MLX5_CAP_GEN(priv->mdev, ets)) | |
50 | return -ENOTSUPP; | |
51 | ||
52 | memcpy(ets, &priv->params.ets, sizeof(*ets)); | |
53 | return 0; | |
54 | } | |
55 | ||
56 | enum { | |
57 | MLX5E_VENDOR_TC_GROUP_NUM = 7, | |
58 | MLX5E_ETS_TC_GROUP_NUM = 0, | |
59 | }; | |
60 | ||
61 | static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc) | |
62 | { | |
63 | bool any_tc_mapped_to_ets = false; | |
64 | int strict_group; | |
65 | int i; | |
66 | ||
67 | for (i = 0; i <= max_tc; i++) | |
68 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) | |
69 | any_tc_mapped_to_ets = true; | |
70 | ||
71 | strict_group = any_tc_mapped_to_ets ? 1 : 0; | |
72 | ||
73 | for (i = 0; i <= max_tc; i++) { | |
74 | switch (ets->tc_tsa[i]) { | |
75 | case IEEE_8021QAZ_TSA_VENDOR: | |
76 | tc_group[i] = MLX5E_VENDOR_TC_GROUP_NUM; | |
77 | break; | |
78 | case IEEE_8021QAZ_TSA_STRICT: | |
79 | tc_group[i] = strict_group++; | |
80 | break; | |
81 | case IEEE_8021QAZ_TSA_ETS: | |
82 | tc_group[i] = MLX5E_ETS_TC_GROUP_NUM; | |
83 | break; | |
84 | } | |
85 | } | |
86 | } | |
87 | ||
88 | static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw, | |
89 | u8 *tc_group, int max_tc) | |
90 | { | |
91 | int i; | |
92 | ||
93 | for (i = 0; i <= max_tc; i++) { | |
94 | switch (ets->tc_tsa[i]) { | |
95 | case IEEE_8021QAZ_TSA_VENDOR: | |
96 | tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; | |
97 | break; | |
98 | case IEEE_8021QAZ_TSA_STRICT: | |
99 | tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; | |
100 | break; | |
101 | case IEEE_8021QAZ_TSA_ETS: | |
cdcf1121 | 102 | tc_tx_bw[i] = ets->tc_tx_bw[i]; |
08fb1dac SM |
103 | break; |
104 | } | |
105 | } | |
106 | } | |
107 | ||
108 | int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets) | |
109 | { | |
110 | struct mlx5_core_dev *mdev = priv->mdev; | |
111 | u8 tc_tx_bw[IEEE_8021QAZ_MAX_TCS]; | |
112 | u8 tc_group[IEEE_8021QAZ_MAX_TCS]; | |
113 | int max_tc = mlx5_max_tc(mdev); | |
114 | int err; | |
115 | ||
116 | if (!MLX5_CAP_GEN(mdev, ets)) | |
117 | return -ENOTSUPP; | |
118 | ||
119 | mlx5e_build_tc_group(ets, tc_group, max_tc); | |
120 | mlx5e_build_tc_tx_bw(ets, tc_tx_bw, tc_group, max_tc); | |
121 | ||
122 | err = mlx5_set_port_prio_tc(mdev, ets->prio_tc); | |
123 | if (err) | |
124 | return err; | |
125 | ||
126 | err = mlx5_set_port_tc_group(mdev, tc_group); | |
127 | if (err) | |
128 | return err; | |
129 | ||
130 | return mlx5_set_port_tc_bw_alloc(mdev, tc_tx_bw); | |
131 | } | |
132 | ||
1722b969 EBE |
133 | static int mlx5e_dbcnl_validate_ets(struct net_device *netdev, |
134 | struct ieee_ets *ets) | |
08fb1dac SM |
135 | { |
136 | int bw_sum = 0; | |
137 | int i; | |
138 | ||
139 | /* Validate Priority */ | |
140 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | |
1722b969 EBE |
141 | if (ets->prio_tc[i] >= MLX5E_MAX_PRIORITY) { |
142 | netdev_err(netdev, | |
143 | "Failed to validate ETS: priority value greater than max(%d)\n", | |
144 | MLX5E_MAX_PRIORITY); | |
08fb1dac | 145 | return -EINVAL; |
1722b969 | 146 | } |
08fb1dac SM |
147 | } |
148 | ||
149 | /* Validate Bandwidth Sum */ | |
150 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | |
cdcf1121 | 151 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { |
1722b969 EBE |
152 | if (!ets->tc_tx_bw[i]) { |
153 | netdev_err(netdev, | |
154 | "Failed to validate ETS: BW 0 is illegal\n"); | |
cdcf1121 | 155 | return -EINVAL; |
1722b969 | 156 | } |
cdcf1121 | 157 | |
08fb1dac | 158 | bw_sum += ets->tc_tx_bw[i]; |
cdcf1121 | 159 | } |
08fb1dac SM |
160 | } |
161 | ||
1722b969 EBE |
162 | if (bw_sum != 0 && bw_sum != 100) { |
163 | netdev_err(netdev, | |
164 | "Failed to validate ETS: BW sum is illegal\n"); | |
08fb1dac | 165 | return -EINVAL; |
1722b969 | 166 | } |
08fb1dac SM |
167 | return 0; |
168 | } | |
169 | ||
170 | static int mlx5e_dcbnl_ieee_setets(struct net_device *netdev, | |
171 | struct ieee_ets *ets) | |
172 | { | |
173 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
174 | int err; | |
175 | ||
1722b969 | 176 | err = mlx5e_dbcnl_validate_ets(netdev, ets); |
08fb1dac SM |
177 | if (err) |
178 | return err; | |
179 | ||
180 | err = mlx5e_dcbnl_ieee_setets_core(priv, ets); | |
181 | if (err) | |
182 | return err; | |
183 | ||
184 | memcpy(&priv->params.ets, ets, sizeof(*ets)); | |
185 | priv->params.ets.ets_cap = mlx5_max_tc(priv->mdev) + 1; | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
ef918433 AS |
190 | static int mlx5e_dcbnl_ieee_getpfc(struct net_device *dev, |
191 | struct ieee_pfc *pfc) | |
192 | { | |
193 | struct mlx5e_priv *priv = netdev_priv(dev); | |
194 | struct mlx5_core_dev *mdev = priv->mdev; | |
cf678570 GP |
195 | struct mlx5e_pport_stats *pstats = &priv->stats.pport; |
196 | int i; | |
ef918433 AS |
197 | |
198 | pfc->pfc_cap = mlx5_max_tc(mdev) + 1; | |
cf678570 GP |
199 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { |
200 | pfc->requests[i] = PPORT_PER_PRIO_GET(pstats, i, tx_pause); | |
201 | pfc->indications[i] = PPORT_PER_PRIO_GET(pstats, i, rx_pause); | |
202 | } | |
ef918433 AS |
203 | |
204 | return mlx5_query_port_pfc(mdev, &pfc->pfc_en, NULL); | |
205 | } | |
206 | ||
207 | static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, | |
208 | struct ieee_pfc *pfc) | |
209 | { | |
210 | struct mlx5e_priv *priv = netdev_priv(dev); | |
211 | struct mlx5_core_dev *mdev = priv->mdev; | |
ef918433 AS |
212 | u8 curr_pfc_en; |
213 | int ret; | |
214 | ||
215 | mlx5_query_port_pfc(mdev, &curr_pfc_en, NULL); | |
216 | ||
217 | if (pfc->pfc_en == curr_pfc_en) | |
218 | return 0; | |
219 | ||
ef918433 | 220 | ret = mlx5_set_port_pfc(mdev, pfc->pfc_en, pfc->pfc_en); |
667daeda | 221 | mlx5_toggle_port_link(mdev); |
ef918433 AS |
222 | |
223 | return ret; | |
224 | } | |
225 | ||
08fb1dac SM |
226 | static u8 mlx5e_dcbnl_getdcbx(struct net_device *dev) |
227 | { | |
3a6a931d HN |
228 | return DCB_CAP_DCBX_HOST | |
229 | DCB_CAP_DCBX_VER_IEEE | | |
230 | DCB_CAP_DCBX_VER_CEE; | |
08fb1dac SM |
231 | } |
232 | ||
233 | static u8 mlx5e_dcbnl_setdcbx(struct net_device *dev, u8 mode) | |
234 | { | |
235 | if ((mode & DCB_CAP_DCBX_LLD_MANAGED) || | |
3a6a931d | 236 | !(mode & DCB_CAP_DCBX_VER_CEE) || |
08fb1dac SM |
237 | !(mode & DCB_CAP_DCBX_VER_IEEE) || |
238 | !(mode & DCB_CAP_DCBX_HOST)) | |
239 | return 1; | |
240 | ||
241 | return 0; | |
242 | } | |
243 | ||
d8880795 TT |
244 | static int mlx5e_dcbnl_ieee_getmaxrate(struct net_device *netdev, |
245 | struct ieee_maxrate *maxrate) | |
246 | { | |
247 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
248 | struct mlx5_core_dev *mdev = priv->mdev; | |
249 | u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; | |
250 | u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; | |
251 | int err; | |
252 | int i; | |
253 | ||
254 | err = mlx5_query_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit); | |
255 | if (err) | |
256 | return err; | |
257 | ||
258 | memset(maxrate->tc_maxrate, 0, sizeof(maxrate->tc_maxrate)); | |
259 | ||
260 | for (i = 0; i <= mlx5_max_tc(mdev); i++) { | |
261 | switch (max_bw_unit[i]) { | |
262 | case MLX5_100_MBPS_UNIT: | |
263 | maxrate->tc_maxrate[i] = max_bw_value[i] * MLX5E_100MB; | |
264 | break; | |
265 | case MLX5_GBPS_UNIT: | |
266 | maxrate->tc_maxrate[i] = max_bw_value[i] * MLX5E_1GB; | |
267 | break; | |
268 | case MLX5_BW_NO_LIMIT: | |
269 | break; | |
270 | default: | |
271 | WARN(true, "non-supported BW unit"); | |
272 | break; | |
273 | } | |
274 | } | |
275 | ||
276 | return 0; | |
277 | } | |
278 | ||
279 | static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev, | |
280 | struct ieee_maxrate *maxrate) | |
281 | { | |
282 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
283 | struct mlx5_core_dev *mdev = priv->mdev; | |
284 | u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; | |
285 | u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; | |
286 | __u64 upper_limit_mbps = roundup(255 * MLX5E_100MB, MLX5E_1GB); | |
287 | int i; | |
288 | ||
289 | memset(max_bw_value, 0, sizeof(max_bw_value)); | |
290 | memset(max_bw_unit, 0, sizeof(max_bw_unit)); | |
291 | ||
292 | for (i = 0; i <= mlx5_max_tc(mdev); i++) { | |
293 | if (!maxrate->tc_maxrate[i]) { | |
294 | max_bw_unit[i] = MLX5_BW_NO_LIMIT; | |
295 | continue; | |
296 | } | |
297 | if (maxrate->tc_maxrate[i] < upper_limit_mbps) { | |
298 | max_bw_value[i] = div_u64(maxrate->tc_maxrate[i], | |
299 | MLX5E_100MB); | |
300 | max_bw_value[i] = max_bw_value[i] ? max_bw_value[i] : 1; | |
301 | max_bw_unit[i] = MLX5_100_MBPS_UNIT; | |
302 | } else { | |
303 | max_bw_value[i] = div_u64(maxrate->tc_maxrate[i], | |
304 | MLX5E_1GB); | |
305 | max_bw_unit[i] = MLX5_GBPS_UNIT; | |
306 | } | |
307 | } | |
308 | ||
309 | return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit); | |
310 | } | |
311 | ||
3a6a931d HN |
312 | static u8 mlx5e_dcbnl_setall(struct net_device *netdev) |
313 | { | |
314 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
315 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
316 | struct mlx5_core_dev *mdev = priv->mdev; | |
317 | struct ieee_ets ets; | |
318 | struct ieee_pfc pfc; | |
319 | int err; | |
320 | int i; | |
321 | ||
322 | memset(&ets, 0, sizeof(ets)); | |
323 | memset(&pfc, 0, sizeof(pfc)); | |
324 | ||
325 | ets.ets_cap = IEEE_8021QAZ_MAX_TCS; | |
326 | for (i = 0; i < CEE_DCBX_MAX_PGS; i++) { | |
327 | ets.tc_tx_bw[i] = cee_cfg->pg_bw_pct[i]; | |
328 | ets.tc_rx_bw[i] = cee_cfg->pg_bw_pct[i]; | |
329 | ets.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; | |
330 | ets.prio_tc[i] = cee_cfg->prio_to_pg_map[i]; | |
331 | } | |
332 | ||
333 | err = mlx5e_dbcnl_validate_ets(netdev, &ets); | |
334 | if (err) { | |
335 | netdev_err(netdev, | |
336 | "%s, Failed to validate ETS: %d\n", __func__, err); | |
337 | goto out; | |
338 | } | |
339 | ||
340 | err = mlx5e_dcbnl_ieee_setets_core(priv, &ets); | |
341 | if (err) { | |
342 | netdev_err(netdev, | |
343 | "%s, Failed to set ETS: %d\n", __func__, err); | |
344 | goto out; | |
345 | } | |
346 | ||
347 | /* Set PFC */ | |
348 | pfc.pfc_cap = mlx5_max_tc(mdev) + 1; | |
349 | if (!cee_cfg->pfc_enable) | |
350 | pfc.pfc_en = 0; | |
351 | else | |
352 | for (i = 0; i < CEE_DCBX_MAX_PRIO; i++) | |
353 | pfc.pfc_en |= cee_cfg->pfc_setting[i] << i; | |
354 | ||
355 | err = mlx5e_dcbnl_ieee_setpfc(netdev, &pfc); | |
356 | if (err) { | |
357 | netdev_err(netdev, | |
358 | "%s, Failed to set PFC: %d\n", __func__, err); | |
359 | goto out; | |
360 | } | |
361 | out: | |
362 | return err ? MLX5_DCB_NO_CHG : MLX5_DCB_CHG_RESET; | |
363 | } | |
364 | ||
365 | static u8 mlx5e_dcbnl_getstate(struct net_device *netdev) | |
366 | { | |
367 | return MLX5E_CEE_STATE_UP; | |
368 | } | |
369 | ||
370 | static void mlx5e_dcbnl_getpermhwaddr(struct net_device *netdev, | |
371 | u8 *perm_addr) | |
372 | { | |
373 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
374 | ||
375 | if (!perm_addr) | |
376 | return; | |
377 | ||
378 | mlx5_query_nic_vport_mac_address(priv->mdev, 0, perm_addr); | |
379 | } | |
380 | ||
381 | static void mlx5e_dcbnl_setpgtccfgtx(struct net_device *netdev, | |
382 | int priority, u8 prio_type, | |
383 | u8 pgid, u8 bw_pct, u8 up_map) | |
384 | { | |
385 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
386 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
387 | ||
388 | if (priority >= CEE_DCBX_MAX_PRIO) { | |
389 | netdev_err(netdev, | |
390 | "%s, priority is out of range\n", __func__); | |
391 | return; | |
392 | } | |
393 | ||
394 | if (pgid >= CEE_DCBX_MAX_PGS) { | |
395 | netdev_err(netdev, | |
396 | "%s, priority group is out of range\n", __func__); | |
397 | return; | |
398 | } | |
399 | ||
400 | cee_cfg->prio_to_pg_map[priority] = pgid; | |
401 | } | |
402 | ||
403 | static void mlx5e_dcbnl_setpgbwgcfgtx(struct net_device *netdev, | |
404 | int pgid, u8 bw_pct) | |
405 | { | |
406 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
407 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
408 | ||
409 | if (pgid >= CEE_DCBX_MAX_PGS) { | |
410 | netdev_err(netdev, | |
411 | "%s, priority group is out of range\n", __func__); | |
412 | return; | |
413 | } | |
414 | ||
415 | cee_cfg->pg_bw_pct[pgid] = bw_pct; | |
416 | } | |
417 | ||
418 | static void mlx5e_dcbnl_getpgtccfgtx(struct net_device *netdev, | |
419 | int priority, u8 *prio_type, | |
420 | u8 *pgid, u8 *bw_pct, u8 *up_map) | |
421 | { | |
422 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
423 | struct mlx5_core_dev *mdev = priv->mdev; | |
424 | ||
425 | if (priority >= CEE_DCBX_MAX_PRIO) { | |
426 | netdev_err(netdev, | |
427 | "%s, priority is out of range\n", __func__); | |
428 | return; | |
429 | } | |
430 | ||
431 | *prio_type = 0; | |
432 | *bw_pct = 0; | |
433 | *up_map = 0; | |
434 | ||
435 | if (mlx5_query_port_prio_tc(mdev, priority, pgid)) | |
436 | *pgid = 0; | |
437 | } | |
438 | ||
439 | static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev, | |
440 | int pgid, u8 *bw_pct) | |
441 | { | |
442 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
443 | struct mlx5_core_dev *mdev = priv->mdev; | |
444 | ||
445 | if (pgid >= CEE_DCBX_MAX_PGS) { | |
446 | netdev_err(netdev, | |
447 | "%s, priority group is out of range\n", __func__); | |
448 | return; | |
449 | } | |
450 | ||
451 | if (mlx5_query_port_tc_bw_alloc(mdev, pgid, bw_pct)) | |
452 | *bw_pct = 0; | |
453 | } | |
454 | ||
455 | static void mlx5e_dcbnl_setpfccfg(struct net_device *netdev, | |
456 | int priority, u8 setting) | |
457 | { | |
458 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
459 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
460 | ||
461 | if (priority >= CEE_DCBX_MAX_PRIO) { | |
462 | netdev_err(netdev, | |
463 | "%s, priority is out of range\n", __func__); | |
464 | return; | |
465 | } | |
466 | ||
467 | if (setting > 1) | |
468 | return; | |
469 | ||
470 | cee_cfg->pfc_setting[priority] = setting; | |
471 | } | |
472 | ||
473 | static int | |
474 | mlx5e_dcbnl_get_priority_pfc(struct net_device *netdev, | |
475 | int priority, u8 *setting) | |
476 | { | |
477 | struct ieee_pfc pfc; | |
478 | int err; | |
479 | ||
480 | err = mlx5e_dcbnl_ieee_getpfc(netdev, &pfc); | |
481 | ||
482 | if (err) | |
483 | *setting = 0; | |
484 | else | |
485 | *setting = (pfc.pfc_en >> priority) & 0x01; | |
486 | ||
487 | return err; | |
488 | } | |
489 | ||
490 | static void mlx5e_dcbnl_getpfccfg(struct net_device *netdev, | |
491 | int priority, u8 *setting) | |
492 | { | |
493 | if (priority >= CEE_DCBX_MAX_PRIO) { | |
494 | netdev_err(netdev, | |
495 | "%s, priority is out of range\n", __func__); | |
496 | return; | |
497 | } | |
498 | ||
499 | if (!setting) | |
500 | return; | |
501 | ||
502 | mlx5e_dcbnl_get_priority_pfc(netdev, priority, setting); | |
503 | } | |
504 | ||
505 | static u8 mlx5e_dcbnl_getcap(struct net_device *netdev, | |
506 | int capid, u8 *cap) | |
507 | { | |
508 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
509 | struct mlx5_core_dev *mdev = priv->mdev; | |
510 | u8 rval = 0; | |
511 | ||
512 | switch (capid) { | |
513 | case DCB_CAP_ATTR_PG: | |
514 | *cap = true; | |
515 | break; | |
516 | case DCB_CAP_ATTR_PFC: | |
517 | *cap = true; | |
518 | break; | |
519 | case DCB_CAP_ATTR_UP2TC: | |
520 | *cap = false; | |
521 | break; | |
522 | case DCB_CAP_ATTR_PG_TCS: | |
523 | *cap = 1 << mlx5_max_tc(mdev); | |
524 | break; | |
525 | case DCB_CAP_ATTR_PFC_TCS: | |
526 | *cap = 1 << mlx5_max_tc(mdev); | |
527 | break; | |
528 | case DCB_CAP_ATTR_GSP: | |
529 | *cap = false; | |
530 | break; | |
531 | case DCB_CAP_ATTR_BCN: | |
532 | *cap = false; | |
533 | break; | |
534 | case DCB_CAP_ATTR_DCBX: | |
535 | *cap = (DCB_CAP_DCBX_LLD_MANAGED | | |
536 | DCB_CAP_DCBX_VER_CEE | | |
537 | DCB_CAP_DCBX_STATIC); | |
538 | break; | |
539 | default: | |
540 | *cap = 0; | |
541 | rval = 1; | |
542 | break; | |
543 | } | |
544 | ||
545 | return rval; | |
546 | } | |
547 | ||
548 | static int mlx5e_dcbnl_getnumtcs(struct net_device *netdev, | |
549 | int tcs_id, u8 *num) | |
550 | { | |
551 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
552 | struct mlx5_core_dev *mdev = priv->mdev; | |
553 | ||
554 | switch (tcs_id) { | |
555 | case DCB_NUMTCS_ATTR_PG: | |
556 | case DCB_NUMTCS_ATTR_PFC: | |
557 | *num = mlx5_max_tc(mdev) + 1; | |
558 | break; | |
559 | default: | |
560 | return -EINVAL; | |
561 | } | |
562 | ||
563 | return 0; | |
564 | } | |
565 | ||
566 | static u8 mlx5e_dcbnl_getpfcstate(struct net_device *netdev) | |
567 | { | |
568 | struct ieee_pfc pfc; | |
569 | ||
570 | if (mlx5e_dcbnl_ieee_getpfc(netdev, &pfc)) | |
571 | return MLX5E_CEE_STATE_DOWN; | |
572 | ||
573 | return pfc.pfc_en ? MLX5E_CEE_STATE_UP : MLX5E_CEE_STATE_DOWN; | |
574 | } | |
575 | ||
576 | static void mlx5e_dcbnl_setpfcstate(struct net_device *netdev, u8 state) | |
577 | { | |
578 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
579 | struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; | |
580 | ||
581 | if ((state != MLX5E_CEE_STATE_UP) && (state != MLX5E_CEE_STATE_DOWN)) | |
582 | return; | |
583 | ||
584 | cee_cfg->pfc_enable = state; | |
585 | } | |
586 | ||
08fb1dac SM |
587 | const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = { |
588 | .ieee_getets = mlx5e_dcbnl_ieee_getets, | |
589 | .ieee_setets = mlx5e_dcbnl_ieee_setets, | |
d8880795 TT |
590 | .ieee_getmaxrate = mlx5e_dcbnl_ieee_getmaxrate, |
591 | .ieee_setmaxrate = mlx5e_dcbnl_ieee_setmaxrate, | |
ef918433 AS |
592 | .ieee_getpfc = mlx5e_dcbnl_ieee_getpfc, |
593 | .ieee_setpfc = mlx5e_dcbnl_ieee_setpfc, | |
08fb1dac SM |
594 | .getdcbx = mlx5e_dcbnl_getdcbx, |
595 | .setdcbx = mlx5e_dcbnl_setdcbx, | |
3a6a931d HN |
596 | |
597 | /* CEE interfaces */ | |
598 | .setall = mlx5e_dcbnl_setall, | |
599 | .getstate = mlx5e_dcbnl_getstate, | |
600 | .getpermhwaddr = mlx5e_dcbnl_getpermhwaddr, | |
601 | ||
602 | .setpgtccfgtx = mlx5e_dcbnl_setpgtccfgtx, | |
603 | .setpgbwgcfgtx = mlx5e_dcbnl_setpgbwgcfgtx, | |
604 | .getpgtccfgtx = mlx5e_dcbnl_getpgtccfgtx, | |
605 | .getpgbwgcfgtx = mlx5e_dcbnl_getpgbwgcfgtx, | |
606 | ||
607 | .setpfccfg = mlx5e_dcbnl_setpfccfg, | |
608 | .getpfccfg = mlx5e_dcbnl_getpfccfg, | |
609 | .getcap = mlx5e_dcbnl_getcap, | |
610 | .getnumtcs = mlx5e_dcbnl_getnumtcs, | |
611 | .getpfcstate = mlx5e_dcbnl_getpfcstate, | |
612 | .setpfcstate = mlx5e_dcbnl_setpfcstate, | |
08fb1dac | 613 | }; |