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