137b6f646SAnirudh Venkataramanan // SPDX-License-Identifier: GPL-2.0
237b6f646SAnirudh Venkataramanan /* Copyright (c) 2019, Intel Corporation. */
337b6f646SAnirudh Venkataramanan 
437b6f646SAnirudh Venkataramanan #include "ice_dcb_lib.h"
537b6f646SAnirudh Venkataramanan 
637b6f646SAnirudh Venkataramanan /**
77b9ffc76SAnirudh Venkataramanan  * ice_dcb_get_ena_tc - return bitmap of enabled TCs
87b9ffc76SAnirudh Venkataramanan  * @dcbcfg: DCB config to evaluate for enabled TCs
97b9ffc76SAnirudh Venkataramanan  */
107b9ffc76SAnirudh Venkataramanan u8 ice_dcb_get_ena_tc(struct ice_dcbx_cfg *dcbcfg)
117b9ffc76SAnirudh Venkataramanan {
127b9ffc76SAnirudh Venkataramanan 	u8 i, num_tc, ena_tc = 1;
137b9ffc76SAnirudh Venkataramanan 
147b9ffc76SAnirudh Venkataramanan 	num_tc = ice_dcb_get_num_tc(dcbcfg);
157b9ffc76SAnirudh Venkataramanan 
167b9ffc76SAnirudh Venkataramanan 	for (i = 0; i < num_tc; i++)
177b9ffc76SAnirudh Venkataramanan 		ena_tc |= BIT(i);
187b9ffc76SAnirudh Venkataramanan 
197b9ffc76SAnirudh Venkataramanan 	return ena_tc;
207b9ffc76SAnirudh Venkataramanan }
217b9ffc76SAnirudh Venkataramanan 
227b9ffc76SAnirudh Venkataramanan /**
237b9ffc76SAnirudh Venkataramanan  * ice_dcb_get_num_tc - Get the number of TCs from DCBX config
247b9ffc76SAnirudh Venkataramanan  * @dcbcfg: config to retrieve number of TCs from
257b9ffc76SAnirudh Venkataramanan  */
267b9ffc76SAnirudh Venkataramanan u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg *dcbcfg)
277b9ffc76SAnirudh Venkataramanan {
287b9ffc76SAnirudh Venkataramanan 	bool tc_unused = false;
297b9ffc76SAnirudh Venkataramanan 	u8 num_tc = 0;
307b9ffc76SAnirudh Venkataramanan 	u8 ret = 0;
317b9ffc76SAnirudh Venkataramanan 	int i;
327b9ffc76SAnirudh Venkataramanan 
337b9ffc76SAnirudh Venkataramanan 	/* Scan the ETS Config Priority Table to find traffic classes
347b9ffc76SAnirudh Venkataramanan 	 * enabled and create a bitmask of enabled TCs
357b9ffc76SAnirudh Venkataramanan 	 */
367b9ffc76SAnirudh Venkataramanan 	for (i = 0; i < CEE_DCBX_MAX_PRIO; i++)
377b9ffc76SAnirudh Venkataramanan 		num_tc |= BIT(dcbcfg->etscfg.prio_table[i]);
387b9ffc76SAnirudh Venkataramanan 
397b9ffc76SAnirudh Venkataramanan 	/* Scan bitmask for contiguous TCs starting with TC0 */
407b9ffc76SAnirudh Venkataramanan 	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
417b9ffc76SAnirudh Venkataramanan 		if (num_tc & BIT(i)) {
427b9ffc76SAnirudh Venkataramanan 			if (!tc_unused) {
437b9ffc76SAnirudh Venkataramanan 				ret++;
447b9ffc76SAnirudh Venkataramanan 			} else {
457b9ffc76SAnirudh Venkataramanan 				pr_err("Non-contiguous TCs - Disabling DCB\n");
467b9ffc76SAnirudh Venkataramanan 				return 1;
477b9ffc76SAnirudh Venkataramanan 			}
487b9ffc76SAnirudh Venkataramanan 		} else {
497b9ffc76SAnirudh Venkataramanan 			tc_unused = true;
507b9ffc76SAnirudh Venkataramanan 		}
517b9ffc76SAnirudh Venkataramanan 	}
527b9ffc76SAnirudh Venkataramanan 
537b9ffc76SAnirudh Venkataramanan 	/* There is always at least 1 TC */
547b9ffc76SAnirudh Venkataramanan 	if (!ret)
557b9ffc76SAnirudh Venkataramanan 		ret = 1;
567b9ffc76SAnirudh Venkataramanan 
577b9ffc76SAnirudh Venkataramanan 	return ret;
587b9ffc76SAnirudh Venkataramanan }
597b9ffc76SAnirudh Venkataramanan 
607b9ffc76SAnirudh Venkataramanan /**
61a629cf0aSAnirudh Venkataramanan  * ice_vsi_cfg_dcb_rings - Update rings to reflect DCB TC
62a629cf0aSAnirudh Venkataramanan  * @vsi: VSI owner of rings being updated
63a629cf0aSAnirudh Venkataramanan  */
64a629cf0aSAnirudh Venkataramanan void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi)
65a629cf0aSAnirudh Venkataramanan {
66a629cf0aSAnirudh Venkataramanan 	struct ice_ring *tx_ring, *rx_ring;
67a629cf0aSAnirudh Venkataramanan 	u16 qoffset, qcount;
68a629cf0aSAnirudh Venkataramanan 	int i, n;
69a629cf0aSAnirudh Venkataramanan 
70a629cf0aSAnirudh Venkataramanan 	if (!test_bit(ICE_FLAG_DCB_ENA, vsi->back->flags)) {
71a629cf0aSAnirudh Venkataramanan 		/* Reset the TC information */
72a629cf0aSAnirudh Venkataramanan 		for (i = 0; i < vsi->num_txq; i++) {
73a629cf0aSAnirudh Venkataramanan 			tx_ring = vsi->tx_rings[i];
74a629cf0aSAnirudh Venkataramanan 			tx_ring->dcb_tc = 0;
75a629cf0aSAnirudh Venkataramanan 		}
76a629cf0aSAnirudh Venkataramanan 		for (i = 0; i < vsi->num_rxq; i++) {
77a629cf0aSAnirudh Venkataramanan 			rx_ring = vsi->rx_rings[i];
78a629cf0aSAnirudh Venkataramanan 			rx_ring->dcb_tc = 0;
79a629cf0aSAnirudh Venkataramanan 		}
80a629cf0aSAnirudh Venkataramanan 		return;
81a629cf0aSAnirudh Venkataramanan 	}
82a629cf0aSAnirudh Venkataramanan 
83a629cf0aSAnirudh Venkataramanan 	ice_for_each_traffic_class(n) {
84a629cf0aSAnirudh Venkataramanan 		if (!(vsi->tc_cfg.ena_tc & BIT(n)))
85a629cf0aSAnirudh Venkataramanan 			break;
86a629cf0aSAnirudh Venkataramanan 
87a629cf0aSAnirudh Venkataramanan 		qoffset = vsi->tc_cfg.tc_info[n].qoffset;
88a629cf0aSAnirudh Venkataramanan 		qcount = vsi->tc_cfg.tc_info[n].qcount_tx;
89a629cf0aSAnirudh Venkataramanan 		for (i = qoffset; i < (qoffset + qcount); i++) {
90a629cf0aSAnirudh Venkataramanan 			tx_ring = vsi->tx_rings[i];
91a629cf0aSAnirudh Venkataramanan 			rx_ring = vsi->rx_rings[i];
92a629cf0aSAnirudh Venkataramanan 			tx_ring->dcb_tc = n;
93a629cf0aSAnirudh Venkataramanan 			rx_ring->dcb_tc = n;
94a629cf0aSAnirudh Venkataramanan 		}
95a629cf0aSAnirudh Venkataramanan 	}
96a629cf0aSAnirudh Venkataramanan }
97a629cf0aSAnirudh Venkataramanan 
98a629cf0aSAnirudh Venkataramanan /**
997b9ffc76SAnirudh Venkataramanan  * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs
1007b9ffc76SAnirudh Venkataramanan  * @pf: pointer to the PF struct
1017b9ffc76SAnirudh Venkataramanan  *
1027b9ffc76SAnirudh Venkataramanan  * Assumed caller has already disabled all VSIs before
1037b9ffc76SAnirudh Venkataramanan  * calling this function. Reconfiguring DCB based on
1047b9ffc76SAnirudh Venkataramanan  * local_dcbx_cfg.
1057b9ffc76SAnirudh Venkataramanan  */
1067b9ffc76SAnirudh Venkataramanan static void ice_pf_dcb_recfg(struct ice_pf *pf)
1077b9ffc76SAnirudh Venkataramanan {
1087b9ffc76SAnirudh Venkataramanan 	struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg;
1097b9ffc76SAnirudh Venkataramanan 	u8 tc_map = 0;
1107b9ffc76SAnirudh Venkataramanan 	int v, ret;
1117b9ffc76SAnirudh Venkataramanan 
1127b9ffc76SAnirudh Venkataramanan 	/* Update each VSI */
1137b9ffc76SAnirudh Venkataramanan 	ice_for_each_vsi(pf, v) {
1147b9ffc76SAnirudh Venkataramanan 		if (!pf->vsi[v])
1157b9ffc76SAnirudh Venkataramanan 			continue;
1167b9ffc76SAnirudh Venkataramanan 
1177b9ffc76SAnirudh Venkataramanan 		if (pf->vsi[v]->type == ICE_VSI_PF)
1187b9ffc76SAnirudh Venkataramanan 			tc_map = ice_dcb_get_ena_tc(dcbcfg);
1197b9ffc76SAnirudh Venkataramanan 		else
1207b9ffc76SAnirudh Venkataramanan 			tc_map = ICE_DFLT_TRAFFIC_CLASS;
1217b9ffc76SAnirudh Venkataramanan 
1227b9ffc76SAnirudh Venkataramanan 		ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map);
1237b9ffc76SAnirudh Venkataramanan 		if (ret)
1247b9ffc76SAnirudh Venkataramanan 			dev_err(&pf->pdev->dev,
1257b9ffc76SAnirudh Venkataramanan 				"Failed to config TC for VSI index: %d\n",
1267b9ffc76SAnirudh Venkataramanan 				pf->vsi[v]->idx);
1277b9ffc76SAnirudh Venkataramanan 		else
1287b9ffc76SAnirudh Venkataramanan 			ice_vsi_map_rings_to_vectors(pf->vsi[v]);
1297b9ffc76SAnirudh Venkataramanan 	}
1307b9ffc76SAnirudh Venkataramanan }
1317b9ffc76SAnirudh Venkataramanan 
1327b9ffc76SAnirudh Venkataramanan /**
1337b9ffc76SAnirudh Venkataramanan  * ice_pf_dcb_cfg - Apply new DCB configuration
1347b9ffc76SAnirudh Venkataramanan  * @pf: pointer to the PF struct
1357b9ffc76SAnirudh Venkataramanan  * @new_cfg: DCBX config to apply
1367b9ffc76SAnirudh Venkataramanan  */
1377b9ffc76SAnirudh Venkataramanan static int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg)
1387b9ffc76SAnirudh Venkataramanan {
1397b9ffc76SAnirudh Venkataramanan 	struct ice_dcbx_cfg *old_cfg, *curr_cfg;
1407b9ffc76SAnirudh Venkataramanan 	struct ice_aqc_port_ets_elem buf = { 0 };
1417b9ffc76SAnirudh Venkataramanan 	int ret = 0;
1427b9ffc76SAnirudh Venkataramanan 
1437b9ffc76SAnirudh Venkataramanan 	curr_cfg = &pf->hw.port_info->local_dcbx_cfg;
1447b9ffc76SAnirudh Venkataramanan 
1457b9ffc76SAnirudh Venkataramanan 	/* Enable DCB tagging only when more than one TC */
1467b9ffc76SAnirudh Venkataramanan 	if (ice_dcb_get_num_tc(new_cfg) > 1) {
1477b9ffc76SAnirudh Venkataramanan 		dev_dbg(&pf->pdev->dev, "DCB tagging enabled (num TC > 1)\n");
1487b9ffc76SAnirudh Venkataramanan 		set_bit(ICE_FLAG_DCB_ENA, pf->flags);
1497b9ffc76SAnirudh Venkataramanan 	} else {
1507b9ffc76SAnirudh Venkataramanan 		dev_dbg(&pf->pdev->dev, "DCB tagging disabled (num TC = 1)\n");
1517b9ffc76SAnirudh Venkataramanan 		clear_bit(ICE_FLAG_DCB_ENA, pf->flags);
1527b9ffc76SAnirudh Venkataramanan 	}
1537b9ffc76SAnirudh Venkataramanan 
1547b9ffc76SAnirudh Venkataramanan 	if (!memcmp(new_cfg, curr_cfg, sizeof(*new_cfg))) {
1557b9ffc76SAnirudh Venkataramanan 		dev_dbg(&pf->pdev->dev, "No change in DCB config required\n");
1567b9ffc76SAnirudh Venkataramanan 		return ret;
1577b9ffc76SAnirudh Venkataramanan 	}
1587b9ffc76SAnirudh Venkataramanan 
1597b9ffc76SAnirudh Venkataramanan 	/* Store old config in case FW config fails */
1607b9ffc76SAnirudh Venkataramanan 	old_cfg = devm_kzalloc(&pf->pdev->dev, sizeof(*old_cfg), GFP_KERNEL);
1617b9ffc76SAnirudh Venkataramanan 	memcpy(old_cfg, curr_cfg, sizeof(*old_cfg));
1627b9ffc76SAnirudh Venkataramanan 
1637b9ffc76SAnirudh Venkataramanan 	/* avoid race conditions by holding the lock while disabling and
1647b9ffc76SAnirudh Venkataramanan 	 * re-enabling the VSI
1657b9ffc76SAnirudh Venkataramanan 	 */
1667b9ffc76SAnirudh Venkataramanan 	rtnl_lock();
1677b9ffc76SAnirudh Venkataramanan 	ice_pf_dis_all_vsi(pf, true);
1687b9ffc76SAnirudh Venkataramanan 
1697b9ffc76SAnirudh Venkataramanan 	memcpy(curr_cfg, new_cfg, sizeof(*curr_cfg));
1707b9ffc76SAnirudh Venkataramanan 	memcpy(&curr_cfg->etsrec, &curr_cfg->etscfg, sizeof(curr_cfg->etsrec));
1717b9ffc76SAnirudh Venkataramanan 
1727b9ffc76SAnirudh Venkataramanan 	/* Only send new config to HW if we are in SW LLDP mode. Otherwise,
1737b9ffc76SAnirudh Venkataramanan 	 * the new config came from the HW in the first place.
1747b9ffc76SAnirudh Venkataramanan 	 */
1757b9ffc76SAnirudh Venkataramanan 	if (pf->hw.port_info->is_sw_lldp) {
1767b9ffc76SAnirudh Venkataramanan 		ret = ice_set_dcb_cfg(pf->hw.port_info);
1777b9ffc76SAnirudh Venkataramanan 		if (ret) {
1787b9ffc76SAnirudh Venkataramanan 			dev_err(&pf->pdev->dev, "Set DCB Config failed\n");
1797b9ffc76SAnirudh Venkataramanan 			/* Restore previous settings to local config */
1807b9ffc76SAnirudh Venkataramanan 			memcpy(curr_cfg, old_cfg, sizeof(*curr_cfg));
1817b9ffc76SAnirudh Venkataramanan 			goto out;
1827b9ffc76SAnirudh Venkataramanan 		}
1837b9ffc76SAnirudh Venkataramanan 	}
1847b9ffc76SAnirudh Venkataramanan 
1857b9ffc76SAnirudh Venkataramanan 	ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL);
1867b9ffc76SAnirudh Venkataramanan 	if (ret) {
1877b9ffc76SAnirudh Venkataramanan 		dev_err(&pf->pdev->dev, "Query Port ETS failed\n");
1887b9ffc76SAnirudh Venkataramanan 		goto out;
1897b9ffc76SAnirudh Venkataramanan 	}
1907b9ffc76SAnirudh Venkataramanan 
1917b9ffc76SAnirudh Venkataramanan 	ice_pf_dcb_recfg(pf);
1927b9ffc76SAnirudh Venkataramanan 
1937b9ffc76SAnirudh Venkataramanan out:
1947b9ffc76SAnirudh Venkataramanan 	ice_pf_ena_all_vsi(pf, true);
1957b9ffc76SAnirudh Venkataramanan 	rtnl_unlock();
1967b9ffc76SAnirudh Venkataramanan 	devm_kfree(&pf->pdev->dev, old_cfg);
1977b9ffc76SAnirudh Venkataramanan 	return ret;
1987b9ffc76SAnirudh Venkataramanan }
1997b9ffc76SAnirudh Venkataramanan 
2007b9ffc76SAnirudh Venkataramanan /**
201b832c2f6SAnirudh Venkataramanan  * ice_dcb_rebuild - rebuild DCB post reset
202b832c2f6SAnirudh Venkataramanan  * @pf: physical function instance
203b832c2f6SAnirudh Venkataramanan  */
204b832c2f6SAnirudh Venkataramanan void ice_dcb_rebuild(struct ice_pf *pf)
205b832c2f6SAnirudh Venkataramanan {
206b832c2f6SAnirudh Venkataramanan 	struct ice_aqc_port_ets_elem buf = { 0 };
207b832c2f6SAnirudh Venkataramanan 	struct ice_dcbx_cfg *prev_cfg;
208b832c2f6SAnirudh Venkataramanan 	enum ice_status ret;
209b832c2f6SAnirudh Venkataramanan 	u8 willing;
210b832c2f6SAnirudh Venkataramanan 
211b832c2f6SAnirudh Venkataramanan 	ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL);
212b832c2f6SAnirudh Venkataramanan 	if (ret) {
213b832c2f6SAnirudh Venkataramanan 		dev_err(&pf->pdev->dev, "Query Port ETS failed\n");
214b832c2f6SAnirudh Venkataramanan 		goto dcb_error;
215b832c2f6SAnirudh Venkataramanan 	}
216b832c2f6SAnirudh Venkataramanan 
217b832c2f6SAnirudh Venkataramanan 	/* If DCB was not enabled previously, we are done */
218b832c2f6SAnirudh Venkataramanan 	if (!test_bit(ICE_FLAG_DCB_ENA, pf->flags))
219b832c2f6SAnirudh Venkataramanan 		return;
220b832c2f6SAnirudh Venkataramanan 
221b832c2f6SAnirudh Venkataramanan 	/* Save current willing state and force FW to unwilling */
222b832c2f6SAnirudh Venkataramanan 	willing = pf->hw.port_info->local_dcbx_cfg.etscfg.willing;
223b832c2f6SAnirudh Venkataramanan 	pf->hw.port_info->local_dcbx_cfg.etscfg.willing = 0x0;
224b832c2f6SAnirudh Venkataramanan 	ret = ice_set_dcb_cfg(pf->hw.port_info);
225b832c2f6SAnirudh Venkataramanan 	if (ret) {
226b832c2f6SAnirudh Venkataramanan 		dev_err(&pf->pdev->dev, "Failed to set DCB to unwilling\n");
227b832c2f6SAnirudh Venkataramanan 		goto dcb_error;
228b832c2f6SAnirudh Venkataramanan 	}
229b832c2f6SAnirudh Venkataramanan 
230b832c2f6SAnirudh Venkataramanan 	/* Retrieve DCB config and ensure same as current in SW */
231b832c2f6SAnirudh Venkataramanan 	prev_cfg = devm_kmemdup(&pf->pdev->dev,
232b832c2f6SAnirudh Venkataramanan 				&pf->hw.port_info->local_dcbx_cfg,
233b832c2f6SAnirudh Venkataramanan 				sizeof(*prev_cfg), GFP_KERNEL);
234b832c2f6SAnirudh Venkataramanan 	if (!prev_cfg) {
235b832c2f6SAnirudh Venkataramanan 		dev_err(&pf->pdev->dev, "Failed to alloc space for DCB cfg\n");
236b832c2f6SAnirudh Venkataramanan 		goto dcb_error;
237b832c2f6SAnirudh Venkataramanan 	}
238b832c2f6SAnirudh Venkataramanan 
239b832c2f6SAnirudh Venkataramanan 	ice_init_dcb(&pf->hw);
240b832c2f6SAnirudh Venkataramanan 	if (memcmp(prev_cfg, &pf->hw.port_info->local_dcbx_cfg,
241b832c2f6SAnirudh Venkataramanan 		   sizeof(*prev_cfg))) {
242b832c2f6SAnirudh Venkataramanan 		/* difference in cfg detected - disable DCB till next MIB */
243b832c2f6SAnirudh Venkataramanan 		dev_err(&pf->pdev->dev, "Set local MIB not accurate\n");
244b832c2f6SAnirudh Venkataramanan 		devm_kfree(&pf->pdev->dev, prev_cfg);
245b832c2f6SAnirudh Venkataramanan 		goto dcb_error;
246b832c2f6SAnirudh Venkataramanan 	}
247b832c2f6SAnirudh Venkataramanan 
248b832c2f6SAnirudh Venkataramanan 	/* fetched config congruent to previous configuration */
249b832c2f6SAnirudh Venkataramanan 	devm_kfree(&pf->pdev->dev, prev_cfg);
250b832c2f6SAnirudh Venkataramanan 
251b832c2f6SAnirudh Venkataramanan 	/* Configuration replayed - reset willing state to previous */
252b832c2f6SAnirudh Venkataramanan 	pf->hw.port_info->local_dcbx_cfg.etscfg.willing = willing;
253b832c2f6SAnirudh Venkataramanan 	ret = ice_set_dcb_cfg(pf->hw.port_info);
254b832c2f6SAnirudh Venkataramanan 	if (ret) {
255b832c2f6SAnirudh Venkataramanan 		dev_err(&pf->pdev->dev, "Fail restoring prev willing state\n");
256b832c2f6SAnirudh Venkataramanan 		goto dcb_error;
257b832c2f6SAnirudh Venkataramanan 	}
258b832c2f6SAnirudh Venkataramanan 	dev_info(&pf->pdev->dev, "DCB restored after reset\n");
259b832c2f6SAnirudh Venkataramanan 	ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL);
260b832c2f6SAnirudh Venkataramanan 	if (ret) {
261b832c2f6SAnirudh Venkataramanan 		dev_err(&pf->pdev->dev, "Query Port ETS failed\n");
262b832c2f6SAnirudh Venkataramanan 		goto dcb_error;
263b832c2f6SAnirudh Venkataramanan 	}
264b832c2f6SAnirudh Venkataramanan 
265b832c2f6SAnirudh Venkataramanan 	return;
266b832c2f6SAnirudh Venkataramanan 
267b832c2f6SAnirudh Venkataramanan dcb_error:
268b832c2f6SAnirudh Venkataramanan 	dev_err(&pf->pdev->dev, "Disabling DCB until new settings occur\n");
269b832c2f6SAnirudh Venkataramanan 	prev_cfg = devm_kzalloc(&pf->pdev->dev, sizeof(*prev_cfg), GFP_KERNEL);
270b832c2f6SAnirudh Venkataramanan 	prev_cfg->etscfg.willing = true;
271b832c2f6SAnirudh Venkataramanan 	prev_cfg->etscfg.tcbwtable[0] = ICE_TC_MAX_BW;
272b832c2f6SAnirudh Venkataramanan 	prev_cfg->etscfg.tsatable[0] = ICE_IEEE_TSA_ETS;
273b832c2f6SAnirudh Venkataramanan 	memcpy(&prev_cfg->etsrec, &prev_cfg->etscfg, sizeof(prev_cfg->etsrec));
274b832c2f6SAnirudh Venkataramanan 	ice_pf_dcb_cfg(pf, prev_cfg);
275b832c2f6SAnirudh Venkataramanan 	devm_kfree(&pf->pdev->dev, prev_cfg);
276b832c2f6SAnirudh Venkataramanan }
277b832c2f6SAnirudh Venkataramanan 
278b832c2f6SAnirudh Venkataramanan /**
2797b9ffc76SAnirudh Venkataramanan  * ice_dcb_init_cfg - set the initial DCB config in SW
2807b9ffc76SAnirudh Venkataramanan  * @pf: pf to apply config to
2817b9ffc76SAnirudh Venkataramanan  */
2827b9ffc76SAnirudh Venkataramanan static int ice_dcb_init_cfg(struct ice_pf *pf)
2837b9ffc76SAnirudh Venkataramanan {
2847b9ffc76SAnirudh Venkataramanan 	struct ice_dcbx_cfg *newcfg;
2857b9ffc76SAnirudh Venkataramanan 	struct ice_port_info *pi;
2867b9ffc76SAnirudh Venkataramanan 	int ret = 0;
2877b9ffc76SAnirudh Venkataramanan 
2887b9ffc76SAnirudh Venkataramanan 	pi = pf->hw.port_info;
2897b9ffc76SAnirudh Venkataramanan 	newcfg = devm_kzalloc(&pf->pdev->dev, sizeof(*newcfg), GFP_KERNEL);
2907b9ffc76SAnirudh Venkataramanan 	if (!newcfg)
2917b9ffc76SAnirudh Venkataramanan 		return -ENOMEM;
2927b9ffc76SAnirudh Venkataramanan 
2937b9ffc76SAnirudh Venkataramanan 	memcpy(newcfg, &pi->local_dcbx_cfg, sizeof(*newcfg));
2947b9ffc76SAnirudh Venkataramanan 	memset(&pi->local_dcbx_cfg, 0, sizeof(*newcfg));
2957b9ffc76SAnirudh Venkataramanan 
2967b9ffc76SAnirudh Venkataramanan 	dev_info(&pf->pdev->dev, "Configuring initial DCB values\n");
2977b9ffc76SAnirudh Venkataramanan 	if (ice_pf_dcb_cfg(pf, newcfg))
2987b9ffc76SAnirudh Venkataramanan 		ret = -EINVAL;
2997b9ffc76SAnirudh Venkataramanan 
3007b9ffc76SAnirudh Venkataramanan 	devm_kfree(&pf->pdev->dev, newcfg);
3017b9ffc76SAnirudh Venkataramanan 
3027b9ffc76SAnirudh Venkataramanan 	return ret;
3037b9ffc76SAnirudh Venkataramanan }
3047b9ffc76SAnirudh Venkataramanan 
3057b9ffc76SAnirudh Venkataramanan /**
3060deab659SAnirudh Venkataramanan  * ice_dcb_sw_default_config - Apply a default DCB config
3070deab659SAnirudh Venkataramanan  * @pf: pf to apply config to
3080deab659SAnirudh Venkataramanan  */
3090deab659SAnirudh Venkataramanan static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf)
3100deab659SAnirudh Venkataramanan {
3110deab659SAnirudh Venkataramanan 	struct ice_aqc_port_ets_elem buf = { 0 };
3120deab659SAnirudh Venkataramanan 	struct ice_dcbx_cfg *dcbcfg;
3130deab659SAnirudh Venkataramanan 	struct ice_port_info *pi;
3140deab659SAnirudh Venkataramanan 	struct ice_hw *hw;
3150deab659SAnirudh Venkataramanan 	int ret;
3160deab659SAnirudh Venkataramanan 
3170deab659SAnirudh Venkataramanan 	hw = &pf->hw;
3180deab659SAnirudh Venkataramanan 	pi = hw->port_info;
3190deab659SAnirudh Venkataramanan 	dcbcfg = devm_kzalloc(&pf->pdev->dev, sizeof(*dcbcfg), GFP_KERNEL);
3200deab659SAnirudh Venkataramanan 
3210deab659SAnirudh Venkataramanan 	memset(dcbcfg, 0, sizeof(*dcbcfg));
3220deab659SAnirudh Venkataramanan 	memset(&pi->local_dcbx_cfg, 0, sizeof(*dcbcfg));
3230deab659SAnirudh Venkataramanan 
3240deab659SAnirudh Venkataramanan 	dcbcfg->etscfg.willing = 1;
3250deab659SAnirudh Venkataramanan 	dcbcfg->etscfg.maxtcs = 8;
3260deab659SAnirudh Venkataramanan 	dcbcfg->etscfg.tcbwtable[0] = 100;
3270deab659SAnirudh Venkataramanan 	dcbcfg->etscfg.tsatable[0] = ICE_IEEE_TSA_ETS;
3280deab659SAnirudh Venkataramanan 
3290deab659SAnirudh Venkataramanan 	memcpy(&dcbcfg->etsrec, &dcbcfg->etscfg,
3300deab659SAnirudh Venkataramanan 	       sizeof(dcbcfg->etsrec));
3310deab659SAnirudh Venkataramanan 	dcbcfg->etsrec.willing = 0;
3320deab659SAnirudh Venkataramanan 
3330deab659SAnirudh Venkataramanan 	dcbcfg->pfc.willing = 1;
3340deab659SAnirudh Venkataramanan 	dcbcfg->pfc.pfccap = IEEE_8021QAZ_MAX_TCS;
3350deab659SAnirudh Venkataramanan 
3360deab659SAnirudh Venkataramanan 	dcbcfg->numapps = 1;
3370deab659SAnirudh Venkataramanan 	dcbcfg->app[0].selector = ICE_APP_SEL_ETHTYPE;
3380deab659SAnirudh Venkataramanan 	dcbcfg->app[0].priority = 3;
3390deab659SAnirudh Venkataramanan 	dcbcfg->app[0].prot_id = ICE_APP_PROT_ID_FCOE;
3400deab659SAnirudh Venkataramanan 
3410deab659SAnirudh Venkataramanan 	ret = ice_pf_dcb_cfg(pf, dcbcfg);
3420deab659SAnirudh Venkataramanan 	devm_kfree(&pf->pdev->dev, dcbcfg);
3430deab659SAnirudh Venkataramanan 	if (ret)
3440deab659SAnirudh Venkataramanan 		return ret;
3450deab659SAnirudh Venkataramanan 
3460deab659SAnirudh Venkataramanan 	return ice_query_port_ets(pi, &buf, sizeof(buf), NULL);
3470deab659SAnirudh Venkataramanan }
3480deab659SAnirudh Venkataramanan 
3490deab659SAnirudh Venkataramanan /**
35037b6f646SAnirudh Venkataramanan  * ice_init_pf_dcb - initialize DCB for a PF
35137b6f646SAnirudh Venkataramanan  * @pf: pf to initiialize DCB for
35237b6f646SAnirudh Venkataramanan  */
35337b6f646SAnirudh Venkataramanan int ice_init_pf_dcb(struct ice_pf *pf)
35437b6f646SAnirudh Venkataramanan {
35537b6f646SAnirudh Venkataramanan 	struct device *dev = &pf->pdev->dev;
35637b6f646SAnirudh Venkataramanan 	struct ice_port_info *port_info;
35737b6f646SAnirudh Venkataramanan 	struct ice_hw *hw = &pf->hw;
3580deab659SAnirudh Venkataramanan 	int sw_default = 0;
3597b9ffc76SAnirudh Venkataramanan 	int err;
36037b6f646SAnirudh Venkataramanan 
36137b6f646SAnirudh Venkataramanan 	port_info = hw->port_info;
36237b6f646SAnirudh Venkataramanan 
36337b6f646SAnirudh Venkataramanan 	/* check if device is DCB capable */
36437b6f646SAnirudh Venkataramanan 	if (!hw->func_caps.common_cap.dcb) {
36537b6f646SAnirudh Venkataramanan 		dev_dbg(dev, "DCB not supported\n");
36637b6f646SAnirudh Venkataramanan 		return -EOPNOTSUPP;
36737b6f646SAnirudh Venkataramanan 	}
36837b6f646SAnirudh Venkataramanan 
36937b6f646SAnirudh Venkataramanan 	/* Best effort to put DCBx and LLDP into a good state */
37037b6f646SAnirudh Venkataramanan 	port_info->dcbx_status = ice_get_dcbx_status(hw);
37137b6f646SAnirudh Venkataramanan 	if (port_info->dcbx_status != ICE_DCBX_STATUS_DONE &&
37237b6f646SAnirudh Venkataramanan 	    port_info->dcbx_status != ICE_DCBX_STATUS_IN_PROGRESS) {
37337b6f646SAnirudh Venkataramanan 		bool dcbx_status;
37437b6f646SAnirudh Venkataramanan 
37537b6f646SAnirudh Venkataramanan 		/* Attempt to start LLDP engine. Ignore errors
37637b6f646SAnirudh Venkataramanan 		 * as this will error if it is already started
37737b6f646SAnirudh Venkataramanan 		 */
37837b6f646SAnirudh Venkataramanan 		ice_aq_start_lldp(hw, NULL);
37937b6f646SAnirudh Venkataramanan 
38037b6f646SAnirudh Venkataramanan 		/* Attempt to start DCBX. Ignore errors as this
38137b6f646SAnirudh Venkataramanan 		 * will error if it is already started
38237b6f646SAnirudh Venkataramanan 		 */
38337b6f646SAnirudh Venkataramanan 		ice_aq_start_stop_dcbx(hw, true, &dcbx_status, NULL);
38437b6f646SAnirudh Venkataramanan 	}
38537b6f646SAnirudh Venkataramanan 
3867b9ffc76SAnirudh Venkataramanan 	err = ice_init_dcb(hw);
3870deab659SAnirudh Venkataramanan 	if (err) {
3880deab659SAnirudh Venkataramanan 		/* FW LLDP not in usable state, default to SW DCBx/LLDP */
3890deab659SAnirudh Venkataramanan 		dev_info(&pf->pdev->dev, "FW LLDP not in usable state\n");
3900deab659SAnirudh Venkataramanan 		hw->port_info->dcbx_status = ICE_DCBX_STATUS_NOT_STARTED;
3910deab659SAnirudh Venkataramanan 		hw->port_info->is_sw_lldp = true;
3920deab659SAnirudh Venkataramanan 	}
3930deab659SAnirudh Venkataramanan 
3940deab659SAnirudh Venkataramanan 	if (port_info->dcbx_status == ICE_DCBX_STATUS_DIS)
3950deab659SAnirudh Venkataramanan 		dev_info(&pf->pdev->dev, "DCBX disabled\n");
3960deab659SAnirudh Venkataramanan 
3970deab659SAnirudh Venkataramanan 	/* LLDP disabled in FW */
3980deab659SAnirudh Venkataramanan 	if (port_info->is_sw_lldp) {
3990deab659SAnirudh Venkataramanan 		sw_default = 1;
4000deab659SAnirudh Venkataramanan 		dev_info(&pf->pdev->dev, "DCBx/LLDP in SW mode.\n");
4010deab659SAnirudh Venkataramanan 	}
4020deab659SAnirudh Venkataramanan 
4030deab659SAnirudh Venkataramanan 	if (port_info->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) {
4040deab659SAnirudh Venkataramanan 		sw_default = 1;
4050deab659SAnirudh Venkataramanan 		dev_info(&pf->pdev->dev, "DCBX not started\n");
4060deab659SAnirudh Venkataramanan 	}
4070deab659SAnirudh Venkataramanan 
4080deab659SAnirudh Venkataramanan 	if (sw_default) {
4090deab659SAnirudh Venkataramanan 		err = ice_dcb_sw_dflt_cfg(pf);
4100deab659SAnirudh Venkataramanan 		if (err) {
4110deab659SAnirudh Venkataramanan 			dev_err(&pf->pdev->dev,
4120deab659SAnirudh Venkataramanan 				"Failed to set local DCB config %d\n", err);
4130deab659SAnirudh Venkataramanan 			err = -EIO;
4147b9ffc76SAnirudh Venkataramanan 			goto dcb_init_err;
4150deab659SAnirudh Venkataramanan 		}
4160deab659SAnirudh Venkataramanan 
4170deab659SAnirudh Venkataramanan 		pf->dcbx_cap = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
4180deab659SAnirudh Venkataramanan 		set_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
4190deab659SAnirudh Venkataramanan 		set_bit(ICE_FLAG_DCB_ENA, pf->flags);
4200deab659SAnirudh Venkataramanan 		return 0;
4210deab659SAnirudh Venkataramanan 	}
4227b9ffc76SAnirudh Venkataramanan 
4237b9ffc76SAnirudh Venkataramanan 	/* DCBX in FW and LLDP enabled in FW */
4247b9ffc76SAnirudh Venkataramanan 	pf->dcbx_cap = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_IEEE;
4257b9ffc76SAnirudh Venkataramanan 
4267b9ffc76SAnirudh Venkataramanan 	set_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
4277b9ffc76SAnirudh Venkataramanan 
4287b9ffc76SAnirudh Venkataramanan 	err = ice_dcb_init_cfg(pf);
4297b9ffc76SAnirudh Venkataramanan 	if (err)
4307b9ffc76SAnirudh Venkataramanan 		goto dcb_init_err;
4317b9ffc76SAnirudh Venkataramanan 
4327b9ffc76SAnirudh Venkataramanan 	dev_info(&pf->pdev->dev, "DCBX offload supported\n");
4337b9ffc76SAnirudh Venkataramanan 	return err;
4347b9ffc76SAnirudh Venkataramanan 
4357b9ffc76SAnirudh Venkataramanan dcb_init_err:
4367b9ffc76SAnirudh Venkataramanan 	dev_err(dev, "DCB init failed\n");
4377b9ffc76SAnirudh Venkataramanan 	return err;
43837b6f646SAnirudh Venkataramanan }
43900cc3f1bSAnirudh Venkataramanan 
44000cc3f1bSAnirudh Venkataramanan /**
4414b0fdcebSAnirudh Venkataramanan  * ice_update_dcb_stats - Update DCB stats counters
4424b0fdcebSAnirudh Venkataramanan  * @pf: PF whose stats needs to be updated
4434b0fdcebSAnirudh Venkataramanan  */
4444b0fdcebSAnirudh Venkataramanan void ice_update_dcb_stats(struct ice_pf *pf)
4454b0fdcebSAnirudh Venkataramanan {
4464b0fdcebSAnirudh Venkataramanan 	struct ice_hw_port_stats *prev_ps, *cur_ps;
4474b0fdcebSAnirudh Venkataramanan 	struct ice_hw *hw = &pf->hw;
4484b0fdcebSAnirudh Venkataramanan 	u8 pf_id = hw->pf_id;
4494b0fdcebSAnirudh Venkataramanan 	int i;
4504b0fdcebSAnirudh Venkataramanan 
4514b0fdcebSAnirudh Venkataramanan 	prev_ps = &pf->stats_prev;
4524b0fdcebSAnirudh Venkataramanan 	cur_ps = &pf->stats;
4534b0fdcebSAnirudh Venkataramanan 
4544b0fdcebSAnirudh Venkataramanan 	for (i = 0; i < 8; i++) {
4554b0fdcebSAnirudh Venkataramanan 		ice_stat_update32(hw, GLPRT_PXOFFRXC(pf_id, i),
4564b0fdcebSAnirudh Venkataramanan 				  pf->stat_prev_loaded,
4574b0fdcebSAnirudh Venkataramanan 				  &prev_ps->priority_xoff_rx[i],
4584b0fdcebSAnirudh Venkataramanan 				  &cur_ps->priority_xoff_rx[i]);
4594b0fdcebSAnirudh Venkataramanan 		ice_stat_update32(hw, GLPRT_PXONRXC(pf_id, i),
4604b0fdcebSAnirudh Venkataramanan 				  pf->stat_prev_loaded,
4614b0fdcebSAnirudh Venkataramanan 				  &prev_ps->priority_xon_rx[i],
4624b0fdcebSAnirudh Venkataramanan 				  &cur_ps->priority_xon_rx[i]);
4634b0fdcebSAnirudh Venkataramanan 		ice_stat_update32(hw, GLPRT_PXONTXC(pf_id, i),
4644b0fdcebSAnirudh Venkataramanan 				  pf->stat_prev_loaded,
4654b0fdcebSAnirudh Venkataramanan 				  &prev_ps->priority_xon_tx[i],
4664b0fdcebSAnirudh Venkataramanan 				  &cur_ps->priority_xon_tx[i]);
4674b0fdcebSAnirudh Venkataramanan 		ice_stat_update32(hw, GLPRT_PXOFFTXC(pf_id, i),
4684b0fdcebSAnirudh Venkataramanan 				  pf->stat_prev_loaded,
4694b0fdcebSAnirudh Venkataramanan 				  &prev_ps->priority_xoff_tx[i],
4704b0fdcebSAnirudh Venkataramanan 				  &cur_ps->priority_xoff_tx[i]);
4714b0fdcebSAnirudh Venkataramanan 		ice_stat_update32(hw, GLPRT_RXON2OFFCNT(pf_id, i),
4724b0fdcebSAnirudh Venkataramanan 				  pf->stat_prev_loaded,
4734b0fdcebSAnirudh Venkataramanan 				  &prev_ps->priority_xon_2_xoff[i],
4744b0fdcebSAnirudh Venkataramanan 				  &cur_ps->priority_xon_2_xoff[i]);
4754b0fdcebSAnirudh Venkataramanan 	}
4764b0fdcebSAnirudh Venkataramanan }
4774b0fdcebSAnirudh Venkataramanan 
4784b0fdcebSAnirudh Venkataramanan /**
4795f6aa50eSAnirudh Venkataramanan  * ice_tx_prepare_vlan_flags_dcb - prepare VLAN tagging for DCB
4805f6aa50eSAnirudh Venkataramanan  * @tx_ring: ring to send buffer on
4815f6aa50eSAnirudh Venkataramanan  * @first: pointer to struct ice_tx_buf
4825f6aa50eSAnirudh Venkataramanan  */
4835f6aa50eSAnirudh Venkataramanan int
4845f6aa50eSAnirudh Venkataramanan ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring,
4855f6aa50eSAnirudh Venkataramanan 			      struct ice_tx_buf *first)
4865f6aa50eSAnirudh Venkataramanan {
4875f6aa50eSAnirudh Venkataramanan 	struct sk_buff *skb = first->skb;
4885f6aa50eSAnirudh Venkataramanan 
4895f6aa50eSAnirudh Venkataramanan 	if (!test_bit(ICE_FLAG_DCB_ENA, tx_ring->vsi->back->flags))
4905f6aa50eSAnirudh Venkataramanan 		return 0;
4915f6aa50eSAnirudh Venkataramanan 
4925f6aa50eSAnirudh Venkataramanan 	/* Insert 802.1p priority into VLAN header */
4935f6aa50eSAnirudh Venkataramanan 	if ((first->tx_flags & (ICE_TX_FLAGS_HW_VLAN | ICE_TX_FLAGS_SW_VLAN)) ||
4945f6aa50eSAnirudh Venkataramanan 	    skb->priority != TC_PRIO_CONTROL) {
4955f6aa50eSAnirudh Venkataramanan 		first->tx_flags &= ~ICE_TX_FLAGS_VLAN_PR_M;
4965f6aa50eSAnirudh Venkataramanan 		/* Mask the lower 3 bits to set the 802.1p priority */
4975f6aa50eSAnirudh Venkataramanan 		first->tx_flags |= (skb->priority & 0x7) <<
4985f6aa50eSAnirudh Venkataramanan 				   ICE_TX_FLAGS_VLAN_PR_S;
4995f6aa50eSAnirudh Venkataramanan 		if (first->tx_flags & ICE_TX_FLAGS_SW_VLAN) {
5005f6aa50eSAnirudh Venkataramanan 			struct vlan_ethhdr *vhdr;
5015f6aa50eSAnirudh Venkataramanan 			int rc;
5025f6aa50eSAnirudh Venkataramanan 
5035f6aa50eSAnirudh Venkataramanan 			rc = skb_cow_head(skb, 0);
5045f6aa50eSAnirudh Venkataramanan 			if (rc < 0)
5055f6aa50eSAnirudh Venkataramanan 				return rc;
5065f6aa50eSAnirudh Venkataramanan 			vhdr = (struct vlan_ethhdr *)skb->data;
5075f6aa50eSAnirudh Venkataramanan 			vhdr->h_vlan_TCI = htons(first->tx_flags >>
5085f6aa50eSAnirudh Venkataramanan 						 ICE_TX_FLAGS_VLAN_S);
5095f6aa50eSAnirudh Venkataramanan 		} else {
5105f6aa50eSAnirudh Venkataramanan 			first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
5115f6aa50eSAnirudh Venkataramanan 		}
5125f6aa50eSAnirudh Venkataramanan 	}
5135f6aa50eSAnirudh Venkataramanan 
5145f6aa50eSAnirudh Venkataramanan 	return 0;
5155f6aa50eSAnirudh Venkataramanan }
5165f6aa50eSAnirudh Venkataramanan 
5175f6aa50eSAnirudh Venkataramanan /**
51800cc3f1bSAnirudh Venkataramanan  * ice_dcb_process_lldp_set_mib_change - Process MIB change
51900cc3f1bSAnirudh Venkataramanan  * @pf: ptr to ice_pf
52000cc3f1bSAnirudh Venkataramanan  * @event: pointer to the admin queue receive event
52100cc3f1bSAnirudh Venkataramanan  */
52200cc3f1bSAnirudh Venkataramanan void
52300cc3f1bSAnirudh Venkataramanan ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf,
52400cc3f1bSAnirudh Venkataramanan 				    struct ice_rq_event_info *event)
52500cc3f1bSAnirudh Venkataramanan {
52600cc3f1bSAnirudh Venkataramanan 	if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) {
52700cc3f1bSAnirudh Venkataramanan 		struct ice_dcbx_cfg *dcbcfg, *prev_cfg;
52800cc3f1bSAnirudh Venkataramanan 		int err;
52900cc3f1bSAnirudh Venkataramanan 
53000cc3f1bSAnirudh Venkataramanan 		prev_cfg = &pf->hw.port_info->local_dcbx_cfg;
53100cc3f1bSAnirudh Venkataramanan 		dcbcfg = devm_kmemdup(&pf->pdev->dev, prev_cfg,
53200cc3f1bSAnirudh Venkataramanan 				      sizeof(*dcbcfg), GFP_KERNEL);
53300cc3f1bSAnirudh Venkataramanan 		if (!dcbcfg)
53400cc3f1bSAnirudh Venkataramanan 			return;
53500cc3f1bSAnirudh Venkataramanan 
53600cc3f1bSAnirudh Venkataramanan 		err = ice_lldp_to_dcb_cfg(event->msg_buf, dcbcfg);
53700cc3f1bSAnirudh Venkataramanan 		if (!err)
53800cc3f1bSAnirudh Venkataramanan 			ice_pf_dcb_cfg(pf, dcbcfg);
53900cc3f1bSAnirudh Venkataramanan 
54000cc3f1bSAnirudh Venkataramanan 		devm_kfree(&pf->pdev->dev, dcbcfg);
54100cc3f1bSAnirudh Venkataramanan 
54200cc3f1bSAnirudh Venkataramanan 		/* Get updated DCBx data from firmware */
54300cc3f1bSAnirudh Venkataramanan 		err = ice_get_dcb_cfg(pf->hw.port_info);
54400cc3f1bSAnirudh Venkataramanan 		if (err)
54500cc3f1bSAnirudh Venkataramanan 			dev_err(&pf->pdev->dev,
54600cc3f1bSAnirudh Venkataramanan 				"Failed to get DCB config\n");
54700cc3f1bSAnirudh Venkataramanan 	} else {
54800cc3f1bSAnirudh Venkataramanan 		dev_dbg(&pf->pdev->dev,
54900cc3f1bSAnirudh Venkataramanan 			"MIB Change Event in HOST mode\n");
55000cc3f1bSAnirudh Venkataramanan 	}
55100cc3f1bSAnirudh Venkataramanan }
552