1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright(c) 1999 - 2018 Intel Corporation. */ |
3 | |
4 | #include "ixgbe.h" |
5 | #include <linux/dcbnl.h> |
6 | #include "ixgbe_dcb_82598.h" |
7 | #include "ixgbe_dcb_82599.h" |
8 | #include "ixgbe_sriov.h" |
9 | |
10 | /* Callbacks for DCB netlink in the kernel */ |
11 | #define BIT_PFC 0x02 |
12 | #define BIT_PG_RX 0x04 |
13 | #define BIT_PG_TX 0x08 |
14 | #define BIT_APP_UPCHG 0x10 |
15 | |
16 | /* Responses for the DCB_C_SET_ALL command */ |
17 | #define DCB_HW_CHG_RST 0 /* DCB configuration changed with reset */ |
18 | #define DCB_NO_HW_CHG 1 /* DCB configuration did not change */ |
19 | #define DCB_HW_CHG 2 /* DCB configuration changed, no reset */ |
20 | |
21 | static int ixgbe_copy_dcb_cfg(struct ixgbe_adapter *adapter, int tc_max) |
22 | { |
23 | struct ixgbe_dcb_config *scfg = &adapter->temp_dcb_cfg; |
24 | struct ixgbe_dcb_config *dcfg = &adapter->dcb_cfg; |
25 | struct tc_configuration *src = NULL; |
26 | struct tc_configuration *dst = NULL; |
27 | int i, j; |
28 | int tx = DCB_TX_CONFIG; |
29 | int rx = DCB_RX_CONFIG; |
30 | int changes = 0; |
31 | #ifdef IXGBE_FCOE |
32 | struct dcb_app app = { |
33 | .selector = DCB_APP_IDTYPE_ETHTYPE, |
34 | .protocol = ETH_P_FCOE, |
35 | }; |
36 | u8 up = dcb_getapp(adapter->netdev, &app); |
37 | |
38 | if (up && !(up & BIT(adapter->fcoe.up))) |
39 | changes |= BIT_APP_UPCHG; |
40 | #endif |
41 | |
42 | for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) { |
43 | src = &scfg->tc_config[i - DCB_PG_ATTR_TC_0]; |
44 | dst = &dcfg->tc_config[i - DCB_PG_ATTR_TC_0]; |
45 | |
46 | if (dst->path[tx].prio_type != src->path[tx].prio_type) { |
47 | dst->path[tx].prio_type = src->path[tx].prio_type; |
48 | changes |= BIT_PG_TX; |
49 | } |
50 | |
51 | if (dst->path[tx].bwg_id != src->path[tx].bwg_id) { |
52 | dst->path[tx].bwg_id = src->path[tx].bwg_id; |
53 | changes |= BIT_PG_TX; |
54 | } |
55 | |
56 | if (dst->path[tx].bwg_percent != src->path[tx].bwg_percent) { |
57 | dst->path[tx].bwg_percent = src->path[tx].bwg_percent; |
58 | changes |= BIT_PG_TX; |
59 | } |
60 | |
61 | if (dst->path[tx].up_to_tc_bitmap != |
62 | src->path[tx].up_to_tc_bitmap) { |
63 | dst->path[tx].up_to_tc_bitmap = |
64 | src->path[tx].up_to_tc_bitmap; |
65 | changes |= (BIT_PG_TX | BIT_PFC | BIT_APP_UPCHG); |
66 | } |
67 | |
68 | if (dst->path[rx].prio_type != src->path[rx].prio_type) { |
69 | dst->path[rx].prio_type = src->path[rx].prio_type; |
70 | changes |= BIT_PG_RX; |
71 | } |
72 | |
73 | if (dst->path[rx].bwg_id != src->path[rx].bwg_id) { |
74 | dst->path[rx].bwg_id = src->path[rx].bwg_id; |
75 | changes |= BIT_PG_RX; |
76 | } |
77 | |
78 | if (dst->path[rx].bwg_percent != src->path[rx].bwg_percent) { |
79 | dst->path[rx].bwg_percent = src->path[rx].bwg_percent; |
80 | changes |= BIT_PG_RX; |
81 | } |
82 | |
83 | if (dst->path[rx].up_to_tc_bitmap != |
84 | src->path[rx].up_to_tc_bitmap) { |
85 | dst->path[rx].up_to_tc_bitmap = |
86 | src->path[rx].up_to_tc_bitmap; |
87 | changes |= (BIT_PG_RX | BIT_PFC | BIT_APP_UPCHG); |
88 | } |
89 | } |
90 | |
91 | for (i = DCB_PG_ATTR_BW_ID_0; i < DCB_PG_ATTR_BW_ID_MAX; i++) { |
92 | j = i - DCB_PG_ATTR_BW_ID_0; |
93 | if (dcfg->bw_percentage[tx][j] != scfg->bw_percentage[tx][j]) { |
94 | dcfg->bw_percentage[tx][j] = scfg->bw_percentage[tx][j]; |
95 | changes |= BIT_PG_TX; |
96 | } |
97 | if (dcfg->bw_percentage[rx][j] != scfg->bw_percentage[rx][j]) { |
98 | dcfg->bw_percentage[rx][j] = scfg->bw_percentage[rx][j]; |
99 | changes |= BIT_PG_RX; |
100 | } |
101 | } |
102 | |
103 | for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) { |
104 | j = i - DCB_PFC_UP_ATTR_0; |
105 | if (dcfg->tc_config[j].dcb_pfc != scfg->tc_config[j].dcb_pfc) { |
106 | dcfg->tc_config[j].dcb_pfc = scfg->tc_config[j].dcb_pfc; |
107 | changes |= BIT_PFC; |
108 | } |
109 | } |
110 | |
111 | if (dcfg->pfc_mode_enable != scfg->pfc_mode_enable) { |
112 | dcfg->pfc_mode_enable = scfg->pfc_mode_enable; |
113 | changes |= BIT_PFC; |
114 | } |
115 | |
116 | return changes; |
117 | } |
118 | |
119 | static u8 ixgbe_dcbnl_get_state(struct net_device *netdev) |
120 | { |
121 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
122 | |
123 | return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); |
124 | } |
125 | |
126 | static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) |
127 | { |
128 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
129 | |
130 | /* Fail command if not in CEE mode */ |
131 | if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) |
132 | return 1; |
133 | |
134 | /* verify there is something to do, if not then exit */ |
135 | if (!state == !(adapter->flags & IXGBE_FLAG_DCB_ENABLED)) |
136 | return 0; |
137 | |
138 | return !!ixgbe_setup_tc(dev: netdev, |
139 | tc: state ? adapter->dcb_cfg.num_tcs.pg_tcs : 0); |
140 | } |
141 | |
142 | static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, |
143 | u8 *perm_addr) |
144 | { |
145 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
146 | int i, j; |
147 | |
148 | memset(perm_addr, 0xff, MAX_ADDR_LEN); |
149 | |
150 | for (i = 0; i < netdev->addr_len; i++) |
151 | perm_addr[i] = adapter->hw.mac.perm_addr[i]; |
152 | |
153 | switch (adapter->hw.mac.type) { |
154 | case ixgbe_mac_82599EB: |
155 | case ixgbe_mac_X540: |
156 | case ixgbe_mac_X550: |
157 | for (j = 0; j < netdev->addr_len; j++, i++) |
158 | perm_addr[i] = adapter->hw.mac.san_addr[j]; |
159 | break; |
160 | default: |
161 | break; |
162 | } |
163 | } |
164 | |
165 | static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, |
166 | u8 prio, u8 bwg_id, u8 bw_pct, |
167 | u8 up_map) |
168 | { |
169 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
170 | |
171 | if (prio != DCB_ATTR_VALUE_UNDEFINED) |
172 | adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type = prio; |
173 | if (bwg_id != DCB_ATTR_VALUE_UNDEFINED) |
174 | adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id = bwg_id; |
175 | if (bw_pct != DCB_ATTR_VALUE_UNDEFINED) |
176 | adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent = |
177 | bw_pct; |
178 | if (up_map != DCB_ATTR_VALUE_UNDEFINED) |
179 | adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap = |
180 | up_map; |
181 | } |
182 | |
183 | static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, |
184 | u8 bw_pct) |
185 | { |
186 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
187 | |
188 | adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; |
189 | } |
190 | |
191 | static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, |
192 | u8 prio, u8 bwg_id, u8 bw_pct, |
193 | u8 up_map) |
194 | { |
195 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
196 | |
197 | if (prio != DCB_ATTR_VALUE_UNDEFINED) |
198 | adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type = prio; |
199 | if (bwg_id != DCB_ATTR_VALUE_UNDEFINED) |
200 | adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id = bwg_id; |
201 | if (bw_pct != DCB_ATTR_VALUE_UNDEFINED) |
202 | adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent = |
203 | bw_pct; |
204 | if (up_map != DCB_ATTR_VALUE_UNDEFINED) |
205 | adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap = |
206 | up_map; |
207 | } |
208 | |
209 | static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, |
210 | u8 bw_pct) |
211 | { |
212 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
213 | |
214 | adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; |
215 | } |
216 | |
217 | static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, |
218 | u8 *prio, u8 *bwg_id, u8 *bw_pct, |
219 | u8 *up_map) |
220 | { |
221 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
222 | |
223 | *prio = adapter->dcb_cfg.tc_config[tc].path[0].prio_type; |
224 | *bwg_id = adapter->dcb_cfg.tc_config[tc].path[0].bwg_id; |
225 | *bw_pct = adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent; |
226 | *up_map = adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap; |
227 | } |
228 | |
229 | static void ixgbe_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, |
230 | u8 *bw_pct) |
231 | { |
232 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
233 | |
234 | *bw_pct = adapter->dcb_cfg.bw_percentage[0][bwg_id]; |
235 | } |
236 | |
237 | static void ixgbe_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int tc, |
238 | u8 *prio, u8 *bwg_id, u8 *bw_pct, |
239 | u8 *up_map) |
240 | { |
241 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
242 | |
243 | *prio = adapter->dcb_cfg.tc_config[tc].path[1].prio_type; |
244 | *bwg_id = adapter->dcb_cfg.tc_config[tc].path[1].bwg_id; |
245 | *bw_pct = adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent; |
246 | *up_map = adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap; |
247 | } |
248 | |
249 | static void ixgbe_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, |
250 | u8 *bw_pct) |
251 | { |
252 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
253 | |
254 | *bw_pct = adapter->dcb_cfg.bw_percentage[1][bwg_id]; |
255 | } |
256 | |
257 | static void ixgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority, |
258 | u8 setting) |
259 | { |
260 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
261 | |
262 | adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting; |
263 | if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc != |
264 | adapter->dcb_cfg.tc_config[priority].dcb_pfc) |
265 | adapter->temp_dcb_cfg.pfc_mode_enable = true; |
266 | } |
267 | |
268 | static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, |
269 | u8 *setting) |
270 | { |
271 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
272 | |
273 | *setting = adapter->dcb_cfg.tc_config[priority].dcb_pfc; |
274 | } |
275 | |
276 | static void ixgbe_dcbnl_devreset(struct net_device *dev) |
277 | { |
278 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
279 | |
280 | while (test_and_set_bit(nr: __IXGBE_RESETTING, addr: &adapter->state)) |
281 | usleep_range(min: 1000, max: 2000); |
282 | |
283 | if (netif_running(dev)) |
284 | dev->netdev_ops->ndo_stop(dev); |
285 | |
286 | ixgbe_clear_interrupt_scheme(adapter); |
287 | ixgbe_init_interrupt_scheme(adapter); |
288 | |
289 | if (netif_running(dev)) |
290 | dev->netdev_ops->ndo_open(dev); |
291 | |
292 | clear_bit(nr: __IXGBE_RESETTING, addr: &adapter->state); |
293 | } |
294 | |
295 | static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) |
296 | { |
297 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
298 | struct ixgbe_dcb_config *dcb_cfg = &adapter->dcb_cfg; |
299 | struct ixgbe_hw *hw = &adapter->hw; |
300 | int ret = DCB_NO_HW_CHG; |
301 | int i; |
302 | |
303 | /* Fail command if not in CEE mode */ |
304 | if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) |
305 | return DCB_NO_HW_CHG; |
306 | |
307 | adapter->dcb_set_bitmap |= ixgbe_copy_dcb_cfg(adapter, |
308 | MAX_TRAFFIC_CLASS); |
309 | if (!adapter->dcb_set_bitmap) |
310 | return DCB_NO_HW_CHG; |
311 | |
312 | if (adapter->dcb_set_bitmap & (BIT_PG_TX|BIT_PG_RX)) { |
313 | u16 refill[MAX_TRAFFIC_CLASS], max[MAX_TRAFFIC_CLASS]; |
314 | u8 bwg_id[MAX_TRAFFIC_CLASS], prio_type[MAX_TRAFFIC_CLASS]; |
315 | /* Priority to TC mapping in CEE case default to 1:1 */ |
316 | u8 prio_tc[MAX_USER_PRIORITY]; |
317 | int max_frame = adapter->netdev->mtu + ETH_HLEN + ETH_FCS_LEN; |
318 | |
319 | #ifdef IXGBE_FCOE |
320 | if (adapter->netdev->features & NETIF_F_FCOE_MTU) |
321 | max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE); |
322 | #endif |
323 | |
324 | ixgbe_dcb_calculate_tc_credits(hw, dcb_cfg, max_frame, |
325 | DCB_TX_CONFIG); |
326 | ixgbe_dcb_calculate_tc_credits(hw, dcb_cfg, max_frame, |
327 | DCB_RX_CONFIG); |
328 | |
329 | ixgbe_dcb_unpack_refill(dcb_cfg, DCB_TX_CONFIG, refill); |
330 | ixgbe_dcb_unpack_max(dcb_cfg, max); |
331 | ixgbe_dcb_unpack_bwgid(dcb_cfg, DCB_TX_CONFIG, bwg_id); |
332 | ixgbe_dcb_unpack_prio(dcb_cfg, DCB_TX_CONFIG, prio_type); |
333 | ixgbe_dcb_unpack_map(dcb_cfg, DCB_TX_CONFIG, prio_tc); |
334 | |
335 | ixgbe_dcb_hw_ets_config(hw, refill, max, bwg_id, |
336 | prio_type, tc_prio: prio_tc); |
337 | |
338 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) |
339 | netdev_set_prio_tc_map(dev: netdev, prio: i, tc: prio_tc[i]); |
340 | |
341 | ret = DCB_HW_CHG_RST; |
342 | } |
343 | |
344 | if (adapter->dcb_set_bitmap & BIT_PFC) { |
345 | if (dcb_cfg->pfc_mode_enable) { |
346 | u8 pfc_en; |
347 | u8 prio_tc[MAX_USER_PRIORITY]; |
348 | |
349 | ixgbe_dcb_unpack_map(dcb_cfg, DCB_TX_CONFIG, prio_tc); |
350 | ixgbe_dcb_unpack_pfc(cfg: dcb_cfg, pfc_en: &pfc_en); |
351 | ixgbe_dcb_hw_pfc_config(hw, pfc_en, tc_prio: prio_tc); |
352 | } else { |
353 | hw->mac.ops.fc_enable(hw); |
354 | } |
355 | |
356 | ixgbe_set_rx_drop_en(adapter); |
357 | |
358 | ret = DCB_HW_CHG; |
359 | } |
360 | |
361 | #ifdef IXGBE_FCOE |
362 | /* Reprogram FCoE hardware offloads when the traffic class |
363 | * FCoE is using changes. This happens if the APP info |
364 | * changes or the up2tc mapping is updated. |
365 | */ |
366 | if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { |
367 | struct dcb_app app = { |
368 | .selector = DCB_APP_IDTYPE_ETHTYPE, |
369 | .protocol = ETH_P_FCOE, |
370 | }; |
371 | u8 up = dcb_getapp(netdev, &app); |
372 | |
373 | adapter->fcoe.up = ffs(up) - 1; |
374 | ixgbe_dcbnl_devreset(dev: netdev); |
375 | ret = DCB_HW_CHG_RST; |
376 | } |
377 | #endif |
378 | |
379 | adapter->dcb_set_bitmap = 0x00; |
380 | return ret; |
381 | } |
382 | |
383 | static u8 ixgbe_dcbnl_getcap(struct net_device *netdev, int capid, u8 *cap) |
384 | { |
385 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
386 | |
387 | switch (capid) { |
388 | case DCB_CAP_ATTR_PG: |
389 | *cap = true; |
390 | break; |
391 | case DCB_CAP_ATTR_PFC: |
392 | *cap = true; |
393 | break; |
394 | case DCB_CAP_ATTR_UP2TC: |
395 | *cap = false; |
396 | break; |
397 | case DCB_CAP_ATTR_PG_TCS: |
398 | *cap = 0x80; |
399 | break; |
400 | case DCB_CAP_ATTR_PFC_TCS: |
401 | *cap = 0x80; |
402 | break; |
403 | case DCB_CAP_ATTR_GSP: |
404 | *cap = true; |
405 | break; |
406 | case DCB_CAP_ATTR_BCN: |
407 | *cap = false; |
408 | break; |
409 | case DCB_CAP_ATTR_DCBX: |
410 | *cap = adapter->dcbx_cap; |
411 | break; |
412 | default: |
413 | *cap = false; |
414 | break; |
415 | } |
416 | |
417 | return 0; |
418 | } |
419 | |
420 | static int ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) |
421 | { |
422 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
423 | |
424 | if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { |
425 | switch (tcid) { |
426 | case DCB_NUMTCS_ATTR_PG: |
427 | *num = adapter->dcb_cfg.num_tcs.pg_tcs; |
428 | break; |
429 | case DCB_NUMTCS_ATTR_PFC: |
430 | *num = adapter->dcb_cfg.num_tcs.pfc_tcs; |
431 | break; |
432 | default: |
433 | return -EINVAL; |
434 | } |
435 | } else { |
436 | return -EINVAL; |
437 | } |
438 | |
439 | return 0; |
440 | } |
441 | |
442 | static int ixgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num) |
443 | { |
444 | return -EINVAL; |
445 | } |
446 | |
447 | static u8 ixgbe_dcbnl_getpfcstate(struct net_device *netdev) |
448 | { |
449 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
450 | |
451 | return adapter->dcb_cfg.pfc_mode_enable; |
452 | } |
453 | |
454 | static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) |
455 | { |
456 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
457 | |
458 | adapter->temp_dcb_cfg.pfc_mode_enable = state; |
459 | } |
460 | |
461 | /** |
462 | * ixgbe_dcbnl_getapp - retrieve the DCBX application user priority |
463 | * @netdev : the corresponding netdev |
464 | * @idtype : identifies the id as ether type or TCP/UDP port number |
465 | * @id: id is either ether type or TCP/UDP port number |
466 | * |
467 | * Returns : on success, returns a non-zero 802.1p user priority bitmap |
468 | * otherwise returns -EINVAL as the invalid user priority bitmap to indicate an |
469 | * error. |
470 | */ |
471 | static int ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) |
472 | { |
473 | struct ixgbe_adapter *adapter = netdev_priv(dev: netdev); |
474 | struct dcb_app app = { |
475 | .selector = idtype, |
476 | .protocol = id, |
477 | }; |
478 | |
479 | if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) |
480 | return -EINVAL; |
481 | |
482 | return dcb_getapp(netdev, &app); |
483 | } |
484 | |
485 | static int ixgbe_dcbnl_ieee_getets(struct net_device *dev, |
486 | struct ieee_ets *ets) |
487 | { |
488 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
489 | struct ieee_ets *my_ets = adapter->ixgbe_ieee_ets; |
490 | |
491 | ets->ets_cap = adapter->dcb_cfg.num_tcs.pg_tcs; |
492 | |
493 | /* No IEEE PFC settings available */ |
494 | if (!my_ets) |
495 | return 0; |
496 | |
497 | ets->cbs = my_ets->cbs; |
498 | memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); |
499 | memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw)); |
500 | memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); |
501 | memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); |
502 | return 0; |
503 | } |
504 | |
505 | static int ixgbe_dcbnl_ieee_setets(struct net_device *dev, |
506 | struct ieee_ets *ets) |
507 | { |
508 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
509 | int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN; |
510 | int i, err; |
511 | __u8 max_tc = 0; |
512 | __u8 map_chg = 0; |
513 | |
514 | if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) |
515 | return -EINVAL; |
516 | |
517 | if (!adapter->ixgbe_ieee_ets) { |
518 | adapter->ixgbe_ieee_ets = kmalloc(size: sizeof(struct ieee_ets), |
519 | GFP_KERNEL); |
520 | if (!adapter->ixgbe_ieee_ets) |
521 | return -ENOMEM; |
522 | |
523 | /* initialize UP2TC mappings to invalid value */ |
524 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) |
525 | adapter->ixgbe_ieee_ets->prio_tc[i] = |
526 | IEEE_8021QAZ_MAX_TCS; |
527 | /* if possible update UP2TC mappings from HW */ |
528 | ixgbe_dcb_read_rtrup2tc(hw: &adapter->hw, |
529 | map: adapter->ixgbe_ieee_ets->prio_tc); |
530 | } |
531 | |
532 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { |
533 | if (ets->prio_tc[i] > max_tc) |
534 | max_tc = ets->prio_tc[i]; |
535 | if (ets->prio_tc[i] != adapter->ixgbe_ieee_ets->prio_tc[i]) |
536 | map_chg = 1; |
537 | } |
538 | |
539 | memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets)); |
540 | |
541 | if (max_tc) |
542 | max_tc++; |
543 | |
544 | if (max_tc > adapter->dcb_cfg.num_tcs.pg_tcs) |
545 | return -EINVAL; |
546 | |
547 | if (max_tc != adapter->hw_tcs) { |
548 | err = ixgbe_setup_tc(dev, tc: max_tc); |
549 | if (err) |
550 | return err; |
551 | } else if (map_chg) { |
552 | ixgbe_dcbnl_devreset(dev); |
553 | } |
554 | |
555 | return ixgbe_dcb_hw_ets(hw: &adapter->hw, ets, max: max_frame); |
556 | } |
557 | |
558 | static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev, |
559 | struct ieee_pfc *pfc) |
560 | { |
561 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
562 | struct ieee_pfc *my_pfc = adapter->ixgbe_ieee_pfc; |
563 | int i; |
564 | |
565 | pfc->pfc_cap = adapter->dcb_cfg.num_tcs.pfc_tcs; |
566 | |
567 | /* No IEEE PFC settings available */ |
568 | if (!my_pfc) |
569 | return 0; |
570 | |
571 | pfc->pfc_en = my_pfc->pfc_en; |
572 | pfc->mbc = my_pfc->mbc; |
573 | pfc->delay = my_pfc->delay; |
574 | |
575 | for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { |
576 | pfc->requests[i] = adapter->stats.pxoffrxc[i]; |
577 | pfc->indications[i] = adapter->stats.pxofftxc[i]; |
578 | } |
579 | |
580 | return 0; |
581 | } |
582 | |
583 | static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev, |
584 | struct ieee_pfc *pfc) |
585 | { |
586 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
587 | struct ixgbe_hw *hw = &adapter->hw; |
588 | u8 *prio_tc; |
589 | int err; |
590 | |
591 | if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) |
592 | return -EINVAL; |
593 | |
594 | if (!adapter->ixgbe_ieee_pfc) { |
595 | adapter->ixgbe_ieee_pfc = kmalloc(size: sizeof(struct ieee_pfc), |
596 | GFP_KERNEL); |
597 | if (!adapter->ixgbe_ieee_pfc) |
598 | return -ENOMEM; |
599 | } |
600 | |
601 | prio_tc = adapter->ixgbe_ieee_ets->prio_tc; |
602 | memcpy(adapter->ixgbe_ieee_pfc, pfc, sizeof(*adapter->ixgbe_ieee_pfc)); |
603 | |
604 | /* Enable link flow control parameters if PFC is disabled */ |
605 | if (pfc->pfc_en) |
606 | err = ixgbe_dcb_hw_pfc_config(hw, pfc_en: pfc->pfc_en, tc_prio: prio_tc); |
607 | else |
608 | err = hw->mac.ops.fc_enable(hw); |
609 | |
610 | ixgbe_set_rx_drop_en(adapter); |
611 | |
612 | return err; |
613 | } |
614 | |
615 | static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev, |
616 | struct dcb_app *app) |
617 | { |
618 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
619 | int err; |
620 | |
621 | if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) |
622 | return -EINVAL; |
623 | |
624 | err = dcb_ieee_setapp(dev, app); |
625 | if (err) |
626 | return err; |
627 | |
628 | #ifdef IXGBE_FCOE |
629 | if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && |
630 | app->protocol == ETH_P_FCOE) { |
631 | u8 app_mask = dcb_ieee_getapp_mask(dev, app); |
632 | |
633 | if (app_mask & BIT(adapter->fcoe.up)) |
634 | return 0; |
635 | |
636 | adapter->fcoe.up = app->priority; |
637 | ixgbe_dcbnl_devreset(dev); |
638 | } |
639 | #endif |
640 | |
641 | /* VF devices should use default UP when available */ |
642 | if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && |
643 | app->protocol == 0) { |
644 | int vf; |
645 | |
646 | adapter->default_up = app->priority; |
647 | |
648 | for (vf = 0; vf < adapter->num_vfs; vf++) { |
649 | struct vf_data_storage *vfinfo = &adapter->vfinfo[vf]; |
650 | |
651 | if (!vfinfo->pf_qos) |
652 | ixgbe_set_vmvir(adapter, vid: vfinfo->pf_vlan, |
653 | qos: app->priority, vf); |
654 | } |
655 | } |
656 | |
657 | return 0; |
658 | } |
659 | |
660 | static int ixgbe_dcbnl_ieee_delapp(struct net_device *dev, |
661 | struct dcb_app *app) |
662 | { |
663 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
664 | int err; |
665 | |
666 | if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) |
667 | return -EINVAL; |
668 | |
669 | err = dcb_ieee_delapp(dev, app); |
670 | |
671 | #ifdef IXGBE_FCOE |
672 | if (!err && app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && |
673 | app->protocol == ETH_P_FCOE) { |
674 | u8 app_mask = dcb_ieee_getapp_mask(dev, app); |
675 | |
676 | if (app_mask & BIT(adapter->fcoe.up)) |
677 | return 0; |
678 | |
679 | adapter->fcoe.up = app_mask ? |
680 | ffs(app_mask) - 1 : IXGBE_FCOE_DEFTC; |
681 | ixgbe_dcbnl_devreset(dev); |
682 | } |
683 | #endif |
684 | /* IF default priority is being removed clear VF default UP */ |
685 | if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && |
686 | app->protocol == 0 && adapter->default_up == app->priority) { |
687 | int vf; |
688 | long unsigned int app_mask = dcb_ieee_getapp_mask(dev, app); |
689 | int qos = app_mask ? find_first_bit(addr: &app_mask, size: 8) : 0; |
690 | |
691 | adapter->default_up = qos; |
692 | |
693 | for (vf = 0; vf < adapter->num_vfs; vf++) { |
694 | struct vf_data_storage *vfinfo = &adapter->vfinfo[vf]; |
695 | |
696 | if (!vfinfo->pf_qos) |
697 | ixgbe_set_vmvir(adapter, vid: vfinfo->pf_vlan, |
698 | qos, vf); |
699 | } |
700 | } |
701 | |
702 | return err; |
703 | } |
704 | |
705 | static u8 ixgbe_dcbnl_getdcbx(struct net_device *dev) |
706 | { |
707 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
708 | return adapter->dcbx_cap; |
709 | } |
710 | |
711 | static u8 ixgbe_dcbnl_setdcbx(struct net_device *dev, u8 mode) |
712 | { |
713 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
714 | struct ieee_ets ets = {0}; |
715 | struct ieee_pfc pfc = {0}; |
716 | int err = 0; |
717 | |
718 | /* no support for LLD_MANAGED modes or CEE+IEEE */ |
719 | if ((mode & DCB_CAP_DCBX_LLD_MANAGED) || |
720 | ((mode & DCB_CAP_DCBX_VER_IEEE) && (mode & DCB_CAP_DCBX_VER_CEE)) || |
721 | !(mode & DCB_CAP_DCBX_HOST)) |
722 | return 1; |
723 | |
724 | if (mode == adapter->dcbx_cap) |
725 | return 0; |
726 | |
727 | adapter->dcbx_cap = mode; |
728 | |
729 | /* ETS and PFC defaults */ |
730 | ets.ets_cap = 8; |
731 | pfc.pfc_cap = 8; |
732 | |
733 | if (mode & DCB_CAP_DCBX_VER_IEEE) { |
734 | ixgbe_dcbnl_ieee_setets(dev, ets: &ets); |
735 | ixgbe_dcbnl_ieee_setpfc(dev, pfc: &pfc); |
736 | } else if (mode & DCB_CAP_DCBX_VER_CEE) { |
737 | u8 mask = BIT_PFC | BIT_PG_TX | BIT_PG_RX | BIT_APP_UPCHG; |
738 | |
739 | adapter->dcb_set_bitmap |= mask; |
740 | ixgbe_dcbnl_set_all(netdev: dev); |
741 | } else { |
742 | /* Drop into single TC mode strict priority as this |
743 | * indicates CEE and IEEE versions are disabled |
744 | */ |
745 | ixgbe_dcbnl_ieee_setets(dev, ets: &ets); |
746 | ixgbe_dcbnl_ieee_setpfc(dev, pfc: &pfc); |
747 | err = ixgbe_setup_tc(dev, tc: 0); |
748 | } |
749 | |
750 | return err ? 1 : 0; |
751 | } |
752 | |
753 | const struct dcbnl_rtnl_ops ixgbe_dcbnl_ops = { |
754 | .ieee_getets = ixgbe_dcbnl_ieee_getets, |
755 | .ieee_setets = ixgbe_dcbnl_ieee_setets, |
756 | .ieee_getpfc = ixgbe_dcbnl_ieee_getpfc, |
757 | .ieee_setpfc = ixgbe_dcbnl_ieee_setpfc, |
758 | .ieee_setapp = ixgbe_dcbnl_ieee_setapp, |
759 | .ieee_delapp = ixgbe_dcbnl_ieee_delapp, |
760 | .getstate = ixgbe_dcbnl_get_state, |
761 | .setstate = ixgbe_dcbnl_set_state, |
762 | .getpermhwaddr = ixgbe_dcbnl_get_perm_hw_addr, |
763 | .setpgtccfgtx = ixgbe_dcbnl_set_pg_tc_cfg_tx, |
764 | .setpgbwgcfgtx = ixgbe_dcbnl_set_pg_bwg_cfg_tx, |
765 | .setpgtccfgrx = ixgbe_dcbnl_set_pg_tc_cfg_rx, |
766 | .setpgbwgcfgrx = ixgbe_dcbnl_set_pg_bwg_cfg_rx, |
767 | .getpgtccfgtx = ixgbe_dcbnl_get_pg_tc_cfg_tx, |
768 | .getpgbwgcfgtx = ixgbe_dcbnl_get_pg_bwg_cfg_tx, |
769 | .getpgtccfgrx = ixgbe_dcbnl_get_pg_tc_cfg_rx, |
770 | .getpgbwgcfgrx = ixgbe_dcbnl_get_pg_bwg_cfg_rx, |
771 | .setpfccfg = ixgbe_dcbnl_set_pfc_cfg, |
772 | .getpfccfg = ixgbe_dcbnl_get_pfc_cfg, |
773 | .setall = ixgbe_dcbnl_set_all, |
774 | .getcap = ixgbe_dcbnl_getcap, |
775 | .getnumtcs = ixgbe_dcbnl_getnumtcs, |
776 | .setnumtcs = ixgbe_dcbnl_setnumtcs, |
777 | .getpfcstate = ixgbe_dcbnl_getpfcstate, |
778 | .setpfcstate = ixgbe_dcbnl_setpfcstate, |
779 | .getapp = ixgbe_dcbnl_getapp, |
780 | .getdcbx = ixgbe_dcbnl_getdcbx, |
781 | .setdcbx = ixgbe_dcbnl_setdcbx, |
782 | }; |
783 | |