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
10static 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 **/
19static 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 **/
34static int i40e_dcbnl_ieee_getets(struct net_device *dev,
35				  struct ieee_ets *ets)
36{
37	struct i40e_pf *pf = i40e_netdev_to_pf(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 **/
72static int i40e_dcbnl_ieee_getpfc(struct net_device *dev,
73				  struct ieee_pfc *pfc)
74{
75	struct i40e_pf *pf = i40e_netdev_to_pf(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, &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 **/
105static 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, &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 **/
153static 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, &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 **/
192static 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(old_cfg, &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, &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 **/
244static 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, &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 **/
307static 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 **/
323static 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(I40E_FLAG_DCB_ENA, 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(I40E_FLAG_DCB_ENA, 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 **/
365static 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 **/
401static 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 **/
431static 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 **/
452static 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 **/
471static 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 **/
499static 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 **/
529static 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 **/
555static 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 **/
574static 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 **/
604static 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 **/
628static 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, &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 **/
651static 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 **/
691static 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 **/
710static 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 **/
721static 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 **/
740static 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 **/
755static 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 **/
777static 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 **/
811static u8 i40e_dcbnl_getdcbx(struct net_device *dev)
812{
813	struct i40e_pf *pf = i40e_netdev_to_pf(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 **/
825static 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(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
837static 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 **/
875void 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(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, DCB_CMD_IEEE_SET, 0, 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 **/
925static 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 **/
947static 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 **/
969static 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 **/
993void 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(new_cfg, &app))
1008			i40e_dcbnl_del_app(pf, &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 **/
1018void i40e_dcbnl_setup(struct i40e_vsi *vsi)
1019{
1020	struct net_device *dev = vsi->netdev;
1021	struct i40e_pf *pf = i40e_netdev_to_pf(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