1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright(c) 2013 - 2021 Intel Corporation. */ |
3 | |
4 | #ifdef CONFIG_I40E_DCB |
5 | #include <net/dcbnl.h> |
6 | #include "i40e.h" |
7 | |
8 | #define I40E_DCBNL_STATUS_SUCCESS 0 |
9 | #define I40E_DCBNL_STATUS_ERROR 1 |
10 | static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg, |
11 | struct i40e_dcb_app_priority_table *app); |
12 | /** |
13 | * i40e_get_pfc_delay - retrieve PFC Link Delay |
14 | * @hw: pointer to hardware struct |
15 | * @delay: holds the PFC Link delay value |
16 | * |
17 | * Returns PFC Link Delay from the PRTDCB_GENC.PFCLDA |
18 | **/ |
19 | static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay) |
20 | { |
21 | u32 val; |
22 | |
23 | val = rd32(hw, I40E_PRTDCB_GENC); |
24 | *delay = FIELD_GET(I40E_PRTDCB_GENC_PFCLDA_MASK, val); |
25 | } |
26 | |
27 | /** |
28 | * i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration |
29 | * @dev: the corresponding netdev |
30 | * @ets: structure to hold the ETS information |
31 | * |
32 | * Returns local IEEE ETS configuration |
33 | **/ |
34 | static int i40e_dcbnl_ieee_getets(struct net_device *dev, |
35 | struct ieee_ets *ets) |
36 | { |
37 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev: dev); |
38 | struct i40e_dcbx_config *dcbxcfg; |
39 | |
40 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) |
41 | return -EINVAL; |
42 | |
43 | dcbxcfg = &pf->hw.local_dcbx_config; |
44 | ets->willing = dcbxcfg->etscfg.willing; |
45 | ets->ets_cap = I40E_MAX_TRAFFIC_CLASS; |
46 | ets->cbs = dcbxcfg->etscfg.cbs; |
47 | memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable, |
48 | sizeof(ets->tc_tx_bw)); |
49 | memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable, |
50 | sizeof(ets->tc_rx_bw)); |
51 | memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable, |
52 | sizeof(ets->tc_tsa)); |
53 | memcpy(ets->prio_tc, dcbxcfg->etscfg.prioritytable, |
54 | sizeof(ets->prio_tc)); |
55 | memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable, |
56 | sizeof(ets->tc_reco_bw)); |
57 | memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable, |
58 | sizeof(ets->tc_reco_tsa)); |
59 | memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prioritytable, |
60 | sizeof(ets->reco_prio_tc)); |
61 | |
62 | return 0; |
63 | } |
64 | |
65 | /** |
66 | * i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration |
67 | * @dev: the corresponding netdev |
68 | * @pfc: structure to hold the PFC information |
69 | * |
70 | * Returns local IEEE PFC configuration |
71 | **/ |
72 | static int i40e_dcbnl_ieee_getpfc(struct net_device *dev, |
73 | struct ieee_pfc *pfc) |
74 | { |
75 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev: dev); |
76 | struct i40e_dcbx_config *dcbxcfg; |
77 | struct i40e_hw *hw = &pf->hw; |
78 | int i; |
79 | |
80 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) |
81 | return -EINVAL; |
82 | |
83 | dcbxcfg = &hw->local_dcbx_config; |
84 | pfc->pfc_cap = dcbxcfg->pfc.pfccap; |
85 | pfc->pfc_en = dcbxcfg->pfc.pfcenable; |
86 | pfc->mbc = dcbxcfg->pfc.mbc; |
87 | i40e_get_pfc_delay(hw, delay: &pfc->delay); |
88 | |
89 | /* Get Requests/Indications */ |
90 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { |
91 | pfc->requests[i] = pf->stats.priority_xoff_tx[i]; |
92 | pfc->indications[i] = pf->stats.priority_xoff_rx[i]; |
93 | } |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | /** |
99 | * i40e_dcbnl_ieee_setets - set IEEE ETS configuration |
100 | * @netdev: the corresponding netdev |
101 | * @ets: structure to hold the ETS information |
102 | * |
103 | * Set IEEE ETS configuration |
104 | **/ |
105 | static int i40e_dcbnl_ieee_setets(struct net_device *netdev, |
106 | struct ieee_ets *ets) |
107 | { |
108 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
109 | struct i40e_dcbx_config *old_cfg; |
110 | int i, ret; |
111 | |
112 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || |
113 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
114 | return -EINVAL; |
115 | |
116 | old_cfg = &pf->hw.local_dcbx_config; |
117 | /* Copy current config into temp */ |
118 | pf->tmp_cfg = *old_cfg; |
119 | |
120 | /* Update the ETS configuration for temp */ |
121 | pf->tmp_cfg.etscfg.willing = ets->willing; |
122 | pf->tmp_cfg.etscfg.maxtcs = I40E_MAX_TRAFFIC_CLASS; |
123 | pf->tmp_cfg.etscfg.cbs = ets->cbs; |
124 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { |
125 | pf->tmp_cfg.etscfg.tcbwtable[i] = ets->tc_tx_bw[i]; |
126 | pf->tmp_cfg.etscfg.tsatable[i] = ets->tc_tsa[i]; |
127 | pf->tmp_cfg.etscfg.prioritytable[i] = ets->prio_tc[i]; |
128 | pf->tmp_cfg.etsrec.tcbwtable[i] = ets->tc_reco_bw[i]; |
129 | pf->tmp_cfg.etsrec.tsatable[i] = ets->tc_reco_tsa[i]; |
130 | pf->tmp_cfg.etsrec.prioritytable[i] = ets->reco_prio_tc[i]; |
131 | } |
132 | |
133 | /* Commit changes to HW */ |
134 | ret = i40e_hw_dcb_config(pf, new_cfg: &pf->tmp_cfg); |
135 | if (ret) { |
136 | dev_info(&pf->pdev->dev, |
137 | "Failed setting DCB ETS configuration err %pe aq_err %s\n" , |
138 | ERR_PTR(ret), |
139 | i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); |
140 | return -EINVAL; |
141 | } |
142 | |
143 | return 0; |
144 | } |
145 | |
146 | /** |
147 | * i40e_dcbnl_ieee_setpfc - set local IEEE PFC configuration |
148 | * @netdev: the corresponding netdev |
149 | * @pfc: structure to hold the PFC information |
150 | * |
151 | * Sets local IEEE PFC configuration |
152 | **/ |
153 | static int i40e_dcbnl_ieee_setpfc(struct net_device *netdev, |
154 | struct ieee_pfc *pfc) |
155 | { |
156 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
157 | struct i40e_dcbx_config *old_cfg; |
158 | int ret; |
159 | |
160 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || |
161 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
162 | return -EINVAL; |
163 | |
164 | old_cfg = &pf->hw.local_dcbx_config; |
165 | /* Copy current config into temp */ |
166 | pf->tmp_cfg = *old_cfg; |
167 | if (pfc->pfc_cap) |
168 | pf->tmp_cfg.pfc.pfccap = pfc->pfc_cap; |
169 | else |
170 | pf->tmp_cfg.pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; |
171 | pf->tmp_cfg.pfc.pfcenable = pfc->pfc_en; |
172 | |
173 | ret = i40e_hw_dcb_config(pf, new_cfg: &pf->tmp_cfg); |
174 | if (ret) { |
175 | dev_info(&pf->pdev->dev, |
176 | "Failed setting DCB PFC configuration err %pe aq_err %s\n" , |
177 | ERR_PTR(ret), |
178 | i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); |
179 | return -EINVAL; |
180 | } |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | /** |
186 | * i40e_dcbnl_ieee_setapp - set local IEEE App configuration |
187 | * @netdev: the corresponding netdev |
188 | * @app: structure to hold the Application information |
189 | * |
190 | * Sets local IEEE App configuration |
191 | **/ |
192 | static int i40e_dcbnl_ieee_setapp(struct net_device *netdev, |
193 | struct dcb_app *app) |
194 | { |
195 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
196 | struct i40e_dcb_app_priority_table new_app; |
197 | struct i40e_dcbx_config *old_cfg; |
198 | int ret; |
199 | |
200 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || |
201 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
202 | return -EINVAL; |
203 | |
204 | old_cfg = &pf->hw.local_dcbx_config; |
205 | if (old_cfg->numapps == I40E_DCBX_MAX_APPS) |
206 | return -EINVAL; |
207 | |
208 | ret = dcb_ieee_setapp(netdev, app); |
209 | if (ret) |
210 | return ret; |
211 | |
212 | new_app.selector = app->selector; |
213 | new_app.protocolid = app->protocol; |
214 | new_app.priority = app->priority; |
215 | /* Already internally available */ |
216 | if (i40e_dcbnl_find_app(cfg: old_cfg, app: &new_app)) |
217 | return 0; |
218 | |
219 | /* Copy current config into temp */ |
220 | pf->tmp_cfg = *old_cfg; |
221 | /* Add the app */ |
222 | pf->tmp_cfg.app[pf->tmp_cfg.numapps++] = new_app; |
223 | |
224 | ret = i40e_hw_dcb_config(pf, new_cfg: &pf->tmp_cfg); |
225 | if (ret) { |
226 | dev_info(&pf->pdev->dev, |
227 | "Failed setting DCB configuration err %pe aq_err %s\n" , |
228 | ERR_PTR(ret), |
229 | i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); |
230 | return -EINVAL; |
231 | } |
232 | |
233 | return 0; |
234 | } |
235 | |
236 | /** |
237 | * i40e_dcbnl_ieee_delapp - delete local IEEE App configuration |
238 | * @netdev: the corresponding netdev |
239 | * @app: structure to hold the Application information |
240 | * |
241 | * Deletes local IEEE App configuration other than the first application |
242 | * required by firmware |
243 | **/ |
244 | static int i40e_dcbnl_ieee_delapp(struct net_device *netdev, |
245 | struct dcb_app *app) |
246 | { |
247 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
248 | struct i40e_dcbx_config *old_cfg; |
249 | int i, j, ret; |
250 | |
251 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || |
252 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
253 | return -EINVAL; |
254 | |
255 | ret = dcb_ieee_delapp(netdev, app); |
256 | if (ret) |
257 | return ret; |
258 | |
259 | old_cfg = &pf->hw.local_dcbx_config; |
260 | /* Need one app for FW so keep it */ |
261 | if (old_cfg->numapps == 1) |
262 | return 0; |
263 | |
264 | /* Copy current config into temp */ |
265 | pf->tmp_cfg = *old_cfg; |
266 | |
267 | /* Find and reset the app */ |
268 | for (i = 1; i < pf->tmp_cfg.numapps; i++) { |
269 | if (app->selector == pf->tmp_cfg.app[i].selector && |
270 | app->protocol == pf->tmp_cfg.app[i].protocolid && |
271 | app->priority == pf->tmp_cfg.app[i].priority) { |
272 | /* Reset the app data */ |
273 | pf->tmp_cfg.app[i].selector = 0; |
274 | pf->tmp_cfg.app[i].protocolid = 0; |
275 | pf->tmp_cfg.app[i].priority = 0; |
276 | break; |
277 | } |
278 | } |
279 | |
280 | /* If the specific DCB app not found */ |
281 | if (i == pf->tmp_cfg.numapps) |
282 | return -EINVAL; |
283 | |
284 | pf->tmp_cfg.numapps--; |
285 | /* Overwrite the tmp_cfg app */ |
286 | for (j = i; j < pf->tmp_cfg.numapps; j++) |
287 | pf->tmp_cfg.app[j] = old_cfg->app[j + 1]; |
288 | |
289 | ret = i40e_hw_dcb_config(pf, new_cfg: &pf->tmp_cfg); |
290 | if (ret) { |
291 | dev_info(&pf->pdev->dev, |
292 | "Failed setting DCB configuration err %pe aq_err %s\n" , |
293 | ERR_PTR(ret), |
294 | i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); |
295 | return -EINVAL; |
296 | } |
297 | |
298 | return 0; |
299 | } |
300 | |
301 | /** |
302 | * i40e_dcbnl_getstate - Get DCB enabled state |
303 | * @netdev: the corresponding netdev |
304 | * |
305 | * Get the current DCB enabled state |
306 | **/ |
307 | static u8 i40e_dcbnl_getstate(struct net_device *netdev) |
308 | { |
309 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
310 | |
311 | dev_dbg(&pf->pdev->dev, "DCB state=%d\n" , |
312 | test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0); |
313 | return test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0; |
314 | } |
315 | |
316 | /** |
317 | * i40e_dcbnl_setstate - Set DCB state |
318 | * @netdev: the corresponding netdev |
319 | * @state: enable or disable |
320 | * |
321 | * Set the DCB state |
322 | **/ |
323 | static u8 i40e_dcbnl_setstate(struct net_device *netdev, u8 state) |
324 | { |
325 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
326 | int ret = I40E_DCBNL_STATUS_SUCCESS; |
327 | |
328 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
329 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
330 | return ret; |
331 | |
332 | dev_dbg(&pf->pdev->dev, "new state=%d current state=%d\n" , |
333 | state, test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0); |
334 | /* Nothing to do */ |
335 | if (!state == !test_bit(I40E_FLAG_DCB_ENA, pf->flags)) |
336 | return ret; |
337 | |
338 | if (i40e_is_sw_dcb(pf)) { |
339 | if (state) { |
340 | set_bit(nr: I40E_FLAG_DCB_ENA, addr: pf->flags); |
341 | memcpy(&pf->hw.desired_dcbx_config, |
342 | &pf->hw.local_dcbx_config, |
343 | sizeof(struct i40e_dcbx_config)); |
344 | } else { |
345 | clear_bit(nr: I40E_FLAG_DCB_ENA, addr: pf->flags); |
346 | } |
347 | } else { |
348 | /* Cannot directly manipulate FW LLDP Agent */ |
349 | ret = I40E_DCBNL_STATUS_ERROR; |
350 | } |
351 | return ret; |
352 | } |
353 | |
354 | /** |
355 | * i40e_dcbnl_set_pg_tc_cfg_tx - Set CEE PG Tx config |
356 | * @netdev: the corresponding netdev |
357 | * @tc: the corresponding traffic class |
358 | * @prio_type: the traffic priority type |
359 | * @bwg_id: the BW group id the traffic class belongs to |
360 | * @bw_pct: the BW percentage for the corresponding BWG |
361 | * @up_map: prio mapped to corresponding tc |
362 | * |
363 | * Set Tx PG settings for CEE mode |
364 | **/ |
365 | static void i40e_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, |
366 | u8 prio_type, u8 bwg_id, u8 bw_pct, |
367 | u8 up_map) |
368 | { |
369 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
370 | int i; |
371 | |
372 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
373 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
374 | return; |
375 | |
376 | /* LLTC not supported yet */ |
377 | if (tc >= I40E_MAX_TRAFFIC_CLASS) |
378 | return; |
379 | |
380 | /* prio_type, bwg_id and bw_pct per UP are not supported */ |
381 | |
382 | /* Use only up_map to map tc */ |
383 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { |
384 | if (up_map & BIT(i)) |
385 | pf->tmp_cfg.etscfg.prioritytable[i] = tc; |
386 | } |
387 | pf->tmp_cfg.etscfg.tsatable[tc] = I40E_IEEE_TSA_ETS; |
388 | dev_dbg(&pf->pdev->dev, |
389 | "Set PG config tc=%d bwg_id=%d prio_type=%d bw_pct=%d up_map=%d\n" , |
390 | tc, bwg_id, prio_type, bw_pct, up_map); |
391 | } |
392 | |
393 | /** |
394 | * i40e_dcbnl_set_pg_bwg_cfg_tx - Set CEE PG Tx BW config |
395 | * @netdev: the corresponding netdev |
396 | * @pgid: the corresponding traffic class |
397 | * @bw_pct: the BW percentage for the specified traffic class |
398 | * |
399 | * Set Tx BW settings for CEE mode |
400 | **/ |
401 | static void i40e_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, |
402 | u8 bw_pct) |
403 | { |
404 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
405 | |
406 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
407 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
408 | return; |
409 | |
410 | /* LLTC not supported yet */ |
411 | if (pgid >= I40E_MAX_TRAFFIC_CLASS) |
412 | return; |
413 | |
414 | pf->tmp_cfg.etscfg.tcbwtable[pgid] = bw_pct; |
415 | dev_dbg(&pf->pdev->dev, "Set PG BW config tc=%d bw_pct=%d\n" , |
416 | pgid, bw_pct); |
417 | } |
418 | |
419 | /** |
420 | * i40e_dcbnl_set_pg_tc_cfg_rx - Set CEE PG Rx config |
421 | * @netdev: the corresponding netdev |
422 | * @prio: the corresponding traffic class |
423 | * @prio_type: the traffic priority type |
424 | * @pgid: the BW group id the traffic class belongs to |
425 | * @bw_pct: the BW percentage for the corresponding BWG |
426 | * @up_map: prio mapped to corresponding tc |
427 | * |
428 | * Set Rx BW settings for CEE mode. The hardware does not support this |
429 | * so we won't allow setting of this parameter. |
430 | **/ |
431 | static void i40e_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, |
432 | int __always_unused prio, |
433 | u8 __always_unused prio_type, |
434 | u8 __always_unused pgid, |
435 | u8 __always_unused bw_pct, |
436 | u8 __always_unused up_map) |
437 | { |
438 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
439 | |
440 | dev_dbg(&pf->pdev->dev, "Rx TC PG Config Not Supported.\n" ); |
441 | } |
442 | |
443 | /** |
444 | * i40e_dcbnl_set_pg_bwg_cfg_rx - Set CEE PG Rx config |
445 | * @netdev: the corresponding netdev |
446 | * @pgid: the corresponding traffic class |
447 | * @bw_pct: the BW percentage for the specified traffic class |
448 | * |
449 | * Set Rx BW settings for CEE mode. The hardware does not support this |
450 | * so we won't allow setting of this parameter. |
451 | **/ |
452 | static void i40e_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int pgid, |
453 | u8 bw_pct) |
454 | { |
455 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
456 | |
457 | dev_dbg(&pf->pdev->dev, "Rx BWG PG Config Not Supported.\n" ); |
458 | } |
459 | |
460 | /** |
461 | * i40e_dcbnl_get_pg_tc_cfg_tx - Get CEE PG Tx config |
462 | * @netdev: the corresponding netdev |
463 | * @prio: the corresponding user priority |
464 | * @prio_type: traffic priority type |
465 | * @pgid: the BW group ID the traffic class belongs to |
466 | * @bw_pct: BW percentage for the corresponding BWG |
467 | * @up_map: prio mapped to corresponding TC |
468 | * |
469 | * Get Tx PG settings for CEE mode |
470 | **/ |
471 | static void i40e_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int prio, |
472 | u8 __always_unused *prio_type, |
473 | u8 *pgid, |
474 | u8 __always_unused *bw_pct, |
475 | u8 __always_unused *up_map) |
476 | { |
477 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
478 | |
479 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
480 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
481 | return; |
482 | |
483 | if (prio >= I40E_MAX_USER_PRIORITY) |
484 | return; |
485 | |
486 | *pgid = pf->hw.local_dcbx_config.etscfg.prioritytable[prio]; |
487 | dev_dbg(&pf->pdev->dev, "Get PG config prio=%d tc=%d\n" , |
488 | prio, *pgid); |
489 | } |
490 | |
491 | /** |
492 | * i40e_dcbnl_get_pg_bwg_cfg_tx - Get CEE PG BW config |
493 | * @netdev: the corresponding netdev |
494 | * @pgid: the corresponding traffic class |
495 | * @bw_pct: the BW percentage for the corresponding TC |
496 | * |
497 | * Get Tx BW settings for given TC in CEE mode |
498 | **/ |
499 | static void i40e_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, |
500 | u8 *bw_pct) |
501 | { |
502 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
503 | |
504 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
505 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
506 | return; |
507 | |
508 | if (pgid >= I40E_MAX_TRAFFIC_CLASS) |
509 | return; |
510 | |
511 | *bw_pct = pf->hw.local_dcbx_config.etscfg.tcbwtable[pgid]; |
512 | dev_dbg(&pf->pdev->dev, "Get PG BW config tc=%d bw_pct=%d\n" , |
513 | pgid, *bw_pct); |
514 | } |
515 | |
516 | /** |
517 | * i40e_dcbnl_get_pg_tc_cfg_rx - Get CEE PG Rx config |
518 | * @netdev: the corresponding netdev |
519 | * @prio: the corresponding user priority |
520 | * @prio_type: the traffic priority type |
521 | * @pgid: the PG ID |
522 | * @bw_pct: the BW percentage for the corresponding BWG |
523 | * @up_map: prio mapped to corresponding TC |
524 | * |
525 | * Get Rx PG settings for CEE mode. The UP2TC map is applied in same |
526 | * manner for Tx and Rx (symmetrical) so return the TC information for |
527 | * given priority accordingly. |
528 | **/ |
529 | static void i40e_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int prio, |
530 | u8 *prio_type, u8 *pgid, u8 *bw_pct, |
531 | u8 *up_map) |
532 | { |
533 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
534 | |
535 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
536 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
537 | return; |
538 | |
539 | if (prio >= I40E_MAX_USER_PRIORITY) |
540 | return; |
541 | |
542 | *pgid = pf->hw.local_dcbx_config.etscfg.prioritytable[prio]; |
543 | } |
544 | |
545 | /** |
546 | * i40e_dcbnl_get_pg_bwg_cfg_rx - Get CEE PG BW Rx config |
547 | * @netdev: the corresponding netdev |
548 | * @pgid: the corresponding traffic class |
549 | * @bw_pct: the BW percentage for the corresponding TC |
550 | * |
551 | * Get Rx BW settings for given TC in CEE mode |
552 | * The adapter doesn't support Rx ETS and runs in strict priority |
553 | * mode in Rx path and hence just return 0. |
554 | **/ |
555 | static void i40e_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int pgid, |
556 | u8 *bw_pct) |
557 | { |
558 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
559 | |
560 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
561 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
562 | return; |
563 | *bw_pct = 0; |
564 | } |
565 | |
566 | /** |
567 | * i40e_dcbnl_set_pfc_cfg - Set CEE PFC configuration |
568 | * @netdev: the corresponding netdev |
569 | * @prio: the corresponding user priority |
570 | * @setting: the PFC setting for given priority |
571 | * |
572 | * Set the PFC enabled/disabled setting for given user priority |
573 | **/ |
574 | static void i40e_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio, |
575 | u8 setting) |
576 | { |
577 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
578 | |
579 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
580 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
581 | return; |
582 | |
583 | if (prio >= I40E_MAX_USER_PRIORITY) |
584 | return; |
585 | |
586 | pf->tmp_cfg.pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; |
587 | if (setting) |
588 | pf->tmp_cfg.pfc.pfcenable |= BIT(prio); |
589 | else |
590 | pf->tmp_cfg.pfc.pfcenable &= ~BIT(prio); |
591 | dev_dbg(&pf->pdev->dev, |
592 | "Set PFC Config up=%d setting=%d pfcenable=0x%x\n" , |
593 | prio, setting, pf->tmp_cfg.pfc.pfcenable); |
594 | } |
595 | |
596 | /** |
597 | * i40e_dcbnl_get_pfc_cfg - Get CEE PFC configuration |
598 | * @netdev: the corresponding netdev |
599 | * @prio: the corresponding user priority |
600 | * @setting: the PFC setting for given priority |
601 | * |
602 | * Get the PFC enabled/disabled setting for given user priority |
603 | **/ |
604 | static void i40e_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio, |
605 | u8 *setting) |
606 | { |
607 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
608 | |
609 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
610 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
611 | return; |
612 | |
613 | if (prio >= I40E_MAX_USER_PRIORITY) |
614 | return; |
615 | |
616 | *setting = (pf->hw.local_dcbx_config.pfc.pfcenable >> prio) & 0x1; |
617 | dev_dbg(&pf->pdev->dev, |
618 | "Get PFC Config up=%d setting=%d pfcenable=0x%x\n" , |
619 | prio, *setting, pf->hw.local_dcbx_config.pfc.pfcenable); |
620 | } |
621 | |
622 | /** |
623 | * i40e_dcbnl_cee_set_all - Commit CEE DCB settings to hardware |
624 | * @netdev: the corresponding netdev |
625 | * |
626 | * Commit the current DCB configuration to hardware |
627 | **/ |
628 | static u8 i40e_dcbnl_cee_set_all(struct net_device *netdev) |
629 | { |
630 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
631 | int err; |
632 | |
633 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
634 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
635 | return I40E_DCBNL_STATUS_ERROR; |
636 | |
637 | dev_dbg(&pf->pdev->dev, "Commit DCB Configuration to the hardware\n" ); |
638 | err = i40e_hw_dcb_config(pf, new_cfg: &pf->tmp_cfg); |
639 | |
640 | return err ? I40E_DCBNL_STATUS_ERROR : I40E_DCBNL_STATUS_SUCCESS; |
641 | } |
642 | |
643 | /** |
644 | * i40e_dcbnl_get_cap - Get DCBX capabilities of adapter |
645 | * @netdev: the corresponding netdev |
646 | * @capid: the capability type |
647 | * @cap: the capability value |
648 | * |
649 | * Return the capability value for a given capability type |
650 | **/ |
651 | static u8 i40e_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) |
652 | { |
653 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
654 | |
655 | if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) |
656 | return I40E_DCBNL_STATUS_ERROR; |
657 | |
658 | switch (capid) { |
659 | case DCB_CAP_ATTR_PG: |
660 | case DCB_CAP_ATTR_PFC: |
661 | *cap = true; |
662 | break; |
663 | case DCB_CAP_ATTR_PG_TCS: |
664 | case DCB_CAP_ATTR_PFC_TCS: |
665 | *cap = 0x80; |
666 | break; |
667 | case DCB_CAP_ATTR_DCBX: |
668 | *cap = pf->dcbx_cap; |
669 | break; |
670 | case DCB_CAP_ATTR_UP2TC: |
671 | case DCB_CAP_ATTR_GSP: |
672 | case DCB_CAP_ATTR_BCN: |
673 | default: |
674 | *cap = false; |
675 | break; |
676 | } |
677 | |
678 | dev_dbg(&pf->pdev->dev, "Get Capability cap=%d capval=0x%x\n" , |
679 | capid, *cap); |
680 | return I40E_DCBNL_STATUS_SUCCESS; |
681 | } |
682 | |
683 | /** |
684 | * i40e_dcbnl_getnumtcs - Get max number of traffic classes supported |
685 | * @netdev: the corresponding netdev |
686 | * @tcid: the TC id |
687 | * @num: total number of TCs supported by the device |
688 | * |
689 | * Return the total number of TCs supported by the adapter |
690 | **/ |
691 | static int i40e_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) |
692 | { |
693 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
694 | |
695 | if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) |
696 | return -EINVAL; |
697 | |
698 | *num = I40E_MAX_TRAFFIC_CLASS; |
699 | return 0; |
700 | } |
701 | |
702 | /** |
703 | * i40e_dcbnl_setnumtcs - Set CEE number of traffic classes |
704 | * @netdev: the corresponding netdev |
705 | * @tcid: the TC id |
706 | * @num: total number of TCs |
707 | * |
708 | * Set the total number of TCs (Unsupported) |
709 | **/ |
710 | static int i40e_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num) |
711 | { |
712 | return -EINVAL; |
713 | } |
714 | |
715 | /** |
716 | * i40e_dcbnl_getpfcstate - Get CEE PFC mode |
717 | * @netdev: the corresponding netdev |
718 | * |
719 | * Get the current PFC enabled state |
720 | **/ |
721 | static u8 i40e_dcbnl_getpfcstate(struct net_device *netdev) |
722 | { |
723 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
724 | |
725 | /* Return enabled if any PFC enabled UP */ |
726 | if (pf->hw.local_dcbx_config.pfc.pfcenable) |
727 | return 1; |
728 | else |
729 | return 0; |
730 | } |
731 | |
732 | /** |
733 | * i40e_dcbnl_setpfcstate - Set CEE PFC mode |
734 | * @netdev: the corresponding netdev |
735 | * @state: required state |
736 | * |
737 | * The PFC state to be set; this is enabled/disabled based on the PFC |
738 | * priority settings and not via this call for i40e driver |
739 | **/ |
740 | static void i40e_dcbnl_setpfcstate(struct net_device *netdev, u8 state) |
741 | { |
742 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
743 | |
744 | dev_dbg(&pf->pdev->dev, "PFC State is modified via PFC config.\n" ); |
745 | } |
746 | |
747 | /** |
748 | * i40e_dcbnl_getapp - Get CEE APP |
749 | * @netdev: the corresponding netdev |
750 | * @idtype: the App selector |
751 | * @id: the App ethtype or port number |
752 | * |
753 | * Return the CEE mode app for the given idtype and id |
754 | **/ |
755 | static int i40e_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) |
756 | { |
757 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
758 | struct dcb_app app = { |
759 | .selector = idtype, |
760 | .protocol = id, |
761 | }; |
762 | |
763 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) || |
764 | (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)) |
765 | return -EINVAL; |
766 | |
767 | return dcb_getapp(netdev, &app); |
768 | } |
769 | |
770 | /** |
771 | * i40e_dcbnl_setdcbx - set required DCBx capability |
772 | * @netdev: the corresponding netdev |
773 | * @mode: new DCB mode managed or CEE+IEEE |
774 | * |
775 | * Set DCBx capability features |
776 | **/ |
777 | static u8 i40e_dcbnl_setdcbx(struct net_device *netdev, u8 mode) |
778 | { |
779 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev); |
780 | |
781 | /* Do not allow to set mode if managed by Firmware */ |
782 | if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) |
783 | return I40E_DCBNL_STATUS_ERROR; |
784 | |
785 | /* No support for LLD_MANAGED modes or CEE+IEEE */ |
786 | if ((mode & DCB_CAP_DCBX_LLD_MANAGED) || |
787 | ((mode & DCB_CAP_DCBX_VER_IEEE) && (mode & DCB_CAP_DCBX_VER_CEE)) || |
788 | !(mode & DCB_CAP_DCBX_HOST)) |
789 | return I40E_DCBNL_STATUS_ERROR; |
790 | |
791 | /* Already set to the given mode no change */ |
792 | if (mode == pf->dcbx_cap) |
793 | return I40E_DCBNL_STATUS_SUCCESS; |
794 | |
795 | pf->dcbx_cap = mode; |
796 | if (mode & DCB_CAP_DCBX_VER_CEE) |
797 | pf->hw.local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; |
798 | else |
799 | pf->hw.local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE; |
800 | |
801 | dev_dbg(&pf->pdev->dev, "mode=%d\n" , mode); |
802 | return I40E_DCBNL_STATUS_SUCCESS; |
803 | } |
804 | |
805 | /** |
806 | * i40e_dcbnl_getdcbx - retrieve current DCBx capability |
807 | * @dev: the corresponding netdev |
808 | * |
809 | * Returns DCBx capability features |
810 | **/ |
811 | static u8 i40e_dcbnl_getdcbx(struct net_device *dev) |
812 | { |
813 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev: dev); |
814 | |
815 | return pf->dcbx_cap; |
816 | } |
817 | |
818 | /** |
819 | * i40e_dcbnl_get_perm_hw_addr - MAC address used by DCBx |
820 | * @dev: the corresponding netdev |
821 | * @perm_addr: buffer to store the MAC address |
822 | * |
823 | * Returns the SAN MAC address used for LLDP exchange |
824 | **/ |
825 | static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev, |
826 | u8 *perm_addr) |
827 | { |
828 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev: dev); |
829 | int i; |
830 | |
831 | memset(perm_addr, 0xff, MAX_ADDR_LEN); |
832 | |
833 | for (i = 0; i < dev->addr_len; i++) |
834 | perm_addr[i] = pf->hw.mac.perm_addr[i]; |
835 | } |
836 | |
837 | static const struct dcbnl_rtnl_ops dcbnl_ops = { |
838 | .ieee_getets = i40e_dcbnl_ieee_getets, |
839 | .ieee_getpfc = i40e_dcbnl_ieee_getpfc, |
840 | .getdcbx = i40e_dcbnl_getdcbx, |
841 | .getpermhwaddr = i40e_dcbnl_get_perm_hw_addr, |
842 | .ieee_setets = i40e_dcbnl_ieee_setets, |
843 | .ieee_setpfc = i40e_dcbnl_ieee_setpfc, |
844 | .ieee_setapp = i40e_dcbnl_ieee_setapp, |
845 | .ieee_delapp = i40e_dcbnl_ieee_delapp, |
846 | .getstate = i40e_dcbnl_getstate, |
847 | .setstate = i40e_dcbnl_setstate, |
848 | .setpgtccfgtx = i40e_dcbnl_set_pg_tc_cfg_tx, |
849 | .setpgbwgcfgtx = i40e_dcbnl_set_pg_bwg_cfg_tx, |
850 | .setpgtccfgrx = i40e_dcbnl_set_pg_tc_cfg_rx, |
851 | .setpgbwgcfgrx = i40e_dcbnl_set_pg_bwg_cfg_rx, |
852 | .getpgtccfgtx = i40e_dcbnl_get_pg_tc_cfg_tx, |
853 | .getpgbwgcfgtx = i40e_dcbnl_get_pg_bwg_cfg_tx, |
854 | .getpgtccfgrx = i40e_dcbnl_get_pg_tc_cfg_rx, |
855 | .getpgbwgcfgrx = i40e_dcbnl_get_pg_bwg_cfg_rx, |
856 | .setpfccfg = i40e_dcbnl_set_pfc_cfg, |
857 | .getpfccfg = i40e_dcbnl_get_pfc_cfg, |
858 | .setall = i40e_dcbnl_cee_set_all, |
859 | .getcap = i40e_dcbnl_get_cap, |
860 | .getnumtcs = i40e_dcbnl_getnumtcs, |
861 | .setnumtcs = i40e_dcbnl_setnumtcs, |
862 | .getpfcstate = i40e_dcbnl_getpfcstate, |
863 | .setpfcstate = i40e_dcbnl_setpfcstate, |
864 | .getapp = i40e_dcbnl_getapp, |
865 | .setdcbx = i40e_dcbnl_setdcbx, |
866 | }; |
867 | |
868 | /** |
869 | * i40e_dcbnl_set_all - set all the apps and ieee data from DCBx config |
870 | * @vsi: the corresponding vsi |
871 | * |
872 | * Set up all the IEEE APPs in the DCBNL App Table and generate event for |
873 | * other settings |
874 | **/ |
875 | void i40e_dcbnl_set_all(struct i40e_vsi *vsi) |
876 | { |
877 | struct net_device *dev = vsi->netdev; |
878 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev: dev); |
879 | struct i40e_dcbx_config *dcbxcfg; |
880 | struct i40e_hw *hw = &pf->hw; |
881 | struct dcb_app sapp; |
882 | u8 prio, tc_map; |
883 | int i; |
884 | |
885 | /* SW DCB taken care by DCBNL set calls */ |
886 | if (pf->dcbx_cap & DCB_CAP_DCBX_HOST) |
887 | return; |
888 | |
889 | /* DCB not enabled */ |
890 | if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) |
891 | return; |
892 | |
893 | /* MFP mode but not an iSCSI PF so return */ |
894 | if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(hw->func_caps.iscsi)) |
895 | return; |
896 | |
897 | dcbxcfg = &hw->local_dcbx_config; |
898 | |
899 | /* Set up all the App TLVs if DCBx is negotiated */ |
900 | for (i = 0; i < dcbxcfg->numapps; i++) { |
901 | prio = dcbxcfg->app[i].priority; |
902 | tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]); |
903 | |
904 | /* Add APP only if the TC is enabled for this VSI */ |
905 | if (tc_map & vsi->tc_config.enabled_tc) { |
906 | sapp.selector = dcbxcfg->app[i].selector; |
907 | sapp.protocol = dcbxcfg->app[i].protocolid; |
908 | sapp.priority = prio; |
909 | dcb_ieee_setapp(dev, &sapp); |
910 | } |
911 | } |
912 | |
913 | /* Notify user-space of the changes */ |
914 | dcbnl_ieee_notify(dev, RTM_SETDCB, cmd: DCB_CMD_IEEE_SET, seq: 0, pid: 0); |
915 | } |
916 | |
917 | /** |
918 | * i40e_dcbnl_vsi_del_app - Delete APP for given VSI |
919 | * @vsi: the corresponding vsi |
920 | * @app: APP to delete |
921 | * |
922 | * Delete given APP from the DCBNL APP table for given |
923 | * VSI |
924 | **/ |
925 | static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi, |
926 | struct i40e_dcb_app_priority_table *app) |
927 | { |
928 | struct net_device *dev = vsi->netdev; |
929 | struct dcb_app sapp; |
930 | |
931 | if (!dev) |
932 | return -EINVAL; |
933 | |
934 | sapp.selector = app->selector; |
935 | sapp.protocol = app->protocolid; |
936 | sapp.priority = app->priority; |
937 | return dcb_ieee_delapp(dev, &sapp); |
938 | } |
939 | |
940 | /** |
941 | * i40e_dcbnl_del_app - Delete APP on all VSIs |
942 | * @pf: the corresponding PF |
943 | * @app: APP to delete |
944 | * |
945 | * Delete given APP from all the VSIs for given PF |
946 | **/ |
947 | static void i40e_dcbnl_del_app(struct i40e_pf *pf, |
948 | struct i40e_dcb_app_priority_table *app) |
949 | { |
950 | struct i40e_vsi *vsi; |
951 | int v, err; |
952 | |
953 | i40e_pf_for_each_vsi(pf, v, vsi) |
954 | if (vsi->netdev) { |
955 | err = i40e_dcbnl_vsi_del_app(vsi, app); |
956 | dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n" , |
957 | vsi->seid, err, app->selector, |
958 | app->protocolid, app->priority); |
959 | } |
960 | } |
961 | |
962 | /** |
963 | * i40e_dcbnl_find_app - Search APP in given DCB config |
964 | * @cfg: DCBX configuration data |
965 | * @app: APP to search for |
966 | * |
967 | * Find given APP in the DCB configuration |
968 | **/ |
969 | static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg, |
970 | struct i40e_dcb_app_priority_table *app) |
971 | { |
972 | int i; |
973 | |
974 | for (i = 0; i < cfg->numapps; i++) { |
975 | if (app->selector == cfg->app[i].selector && |
976 | app->protocolid == cfg->app[i].protocolid && |
977 | app->priority == cfg->app[i].priority) |
978 | return true; |
979 | } |
980 | |
981 | return false; |
982 | } |
983 | |
984 | /** |
985 | * i40e_dcbnl_flush_apps - Delete all removed APPs |
986 | * @pf: the corresponding PF |
987 | * @old_cfg: old DCBX configuration data |
988 | * @new_cfg: new DCBX configuration data |
989 | * |
990 | * Find and delete all APPs that are not present in the passed |
991 | * DCB configuration |
992 | **/ |
993 | void i40e_dcbnl_flush_apps(struct i40e_pf *pf, |
994 | struct i40e_dcbx_config *old_cfg, |
995 | struct i40e_dcbx_config *new_cfg) |
996 | { |
997 | struct i40e_dcb_app_priority_table app; |
998 | int i; |
999 | |
1000 | /* MFP mode but not an iSCSI PF so return */ |
1001 | if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(pf->hw.func_caps.iscsi)) |
1002 | return; |
1003 | |
1004 | for (i = 0; i < old_cfg->numapps; i++) { |
1005 | app = old_cfg->app[i]; |
1006 | /* The APP is not available anymore delete it */ |
1007 | if (!i40e_dcbnl_find_app(cfg: new_cfg, app: &app)) |
1008 | i40e_dcbnl_del_app(pf, app: &app); |
1009 | } |
1010 | } |
1011 | |
1012 | /** |
1013 | * i40e_dcbnl_setup - DCBNL setup |
1014 | * @vsi: the corresponding vsi |
1015 | * |
1016 | * Set up DCBNL ops and initial APP TLVs |
1017 | **/ |
1018 | void i40e_dcbnl_setup(struct i40e_vsi *vsi) |
1019 | { |
1020 | struct net_device *dev = vsi->netdev; |
1021 | struct i40e_pf *pf = i40e_netdev_to_pf(netdev: dev); |
1022 | |
1023 | /* Not DCB capable */ |
1024 | if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) |
1025 | return; |
1026 | |
1027 | dev->dcbnl_ops = &dcbnl_ops; |
1028 | |
1029 | /* Set initial IEEE DCB settings */ |
1030 | i40e_dcbnl_set_all(vsi); |
1031 | } |
1032 | #endif /* CONFIG_I40E_DCB */ |
1033 | |