xref: /linux/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c (revision b5bee6ced21ca98389000b7017dd41b0cc37fa50)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2013 - 2021 Intel Corporation. */
3 
4 #ifdef CONFIG_I40E_DCB
5 #include "i40e.h"
6 #include <net/dcbnl.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(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(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, &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, &pf->tmp_cfg);
136 	if (ret) {
137 		dev_info(&pf->pdev->dev,
138 			 "Failed setting DCB ETS configuration err %s aq_err %s\n",
139 			 i40e_stat_str(&pf->hw, 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, &pf->tmp_cfg);
175 	if (ret) {
176 		dev_info(&pf->pdev->dev,
177 			 "Failed setting DCB PFC configuration err %s aq_err %s\n",
178 			 i40e_stat_str(&pf->hw, 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(old_cfg, &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, &pf->tmp_cfg);
226 	if (ret) {
227 		dev_info(&pf->pdev->dev,
228 			 "Failed setting DCB configuration err %s aq_err %s\n",
229 			 i40e_stat_str(&pf->hw, 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, &pf->tmp_cfg);
291 	if (ret) {
292 		dev_info(&pf->pdev->dev,
293 			 "Failed setting DCB configuration err %s aq_err %s\n",
294 			 i40e_stat_str(&pf->hw, 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, &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(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(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(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, DCB_CMD_IEEE_SET, 0, 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(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(new_cfg, &app))
1012 			i40e_dcbnl_del_app(pf, &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(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