xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/nic/dcb.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1*9b7fe804SBin Chen // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*9b7fe804SBin Chen /* Copyright (C) 2023 Corigine, Inc. */
3*9b7fe804SBin Chen 
4*9b7fe804SBin Chen #include <linux/device.h>
5*9b7fe804SBin Chen #include <linux/netdevice.h>
6*9b7fe804SBin Chen #include <net/dcbnl.h>
7*9b7fe804SBin Chen 
8*9b7fe804SBin Chen #include "../nfp_app.h"
9*9b7fe804SBin Chen #include "../nfp_net.h"
10*9b7fe804SBin Chen #include "../nfp_main.h"
11*9b7fe804SBin Chen #include "../nfpcore/nfp_cpp.h"
12*9b7fe804SBin Chen #include "../nfpcore/nfp_nffw.h"
13*9b7fe804SBin Chen #include "../nfp_net_sriov.h"
14*9b7fe804SBin Chen 
15*9b7fe804SBin Chen #include "main.h"
16*9b7fe804SBin Chen 
17*9b7fe804SBin Chen #define NFP_DCB_TRUST_PCP	1
18*9b7fe804SBin Chen #define NFP_DCB_TRUST_DSCP	2
19*9b7fe804SBin Chen #define NFP_DCB_TRUST_INVALID	0xff
20*9b7fe804SBin Chen 
21*9b7fe804SBin Chen #define NFP_DCB_TSA_VENDOR	1
22*9b7fe804SBin Chen #define NFP_DCB_TSA_STRICT	2
23*9b7fe804SBin Chen #define NFP_DCB_TSA_ETS		3
24*9b7fe804SBin Chen 
25*9b7fe804SBin Chen #define NFP_DCB_GBL_ENABLE	BIT(0)
26*9b7fe804SBin Chen #define NFP_DCB_QOS_ENABLE	BIT(1)
27*9b7fe804SBin Chen #define NFP_DCB_DISABLE		0
28*9b7fe804SBin Chen #define NFP_DCB_ALL_QOS_ENABLE	(NFP_DCB_GBL_ENABLE | NFP_DCB_QOS_ENABLE)
29*9b7fe804SBin Chen 
30*9b7fe804SBin Chen #define NFP_DCB_UPDATE_MSK_SZ	4
31*9b7fe804SBin Chen #define NFP_DCB_TC_RATE_MAX	0xffff
32*9b7fe804SBin Chen 
33*9b7fe804SBin Chen #define NFP_DCB_DATA_OFF_DSCP2IDX	0
34*9b7fe804SBin Chen #define NFP_DCB_DATA_OFF_PCP2IDX	64
35*9b7fe804SBin Chen #define NFP_DCB_DATA_OFF_TSA		80
36*9b7fe804SBin Chen #define NFP_DCB_DATA_OFF_IDX_BW_PCT	88
37*9b7fe804SBin Chen #define NFP_DCB_DATA_OFF_RATE		96
38*9b7fe804SBin Chen #define NFP_DCB_DATA_OFF_CAP		112
39*9b7fe804SBin Chen #define NFP_DCB_DATA_OFF_ENABLE		116
40*9b7fe804SBin Chen #define NFP_DCB_DATA_OFF_TRUST		120
41*9b7fe804SBin Chen 
42*9b7fe804SBin Chen #define NFP_DCB_MSG_MSK_ENABLE	BIT(31)
43*9b7fe804SBin Chen #define NFP_DCB_MSG_MSK_TRUST	BIT(30)
44*9b7fe804SBin Chen #define NFP_DCB_MSG_MSK_TSA	BIT(29)
45*9b7fe804SBin Chen #define NFP_DCB_MSG_MSK_DSCP	BIT(28)
46*9b7fe804SBin Chen #define NFP_DCB_MSG_MSK_PCP	BIT(27)
47*9b7fe804SBin Chen #define NFP_DCB_MSG_MSK_RATE	BIT(26)
48*9b7fe804SBin Chen #define NFP_DCB_MSG_MSK_PCT	BIT(25)
49*9b7fe804SBin Chen 
get_dcb_priv(struct nfp_net * nn)50*9b7fe804SBin Chen static struct nfp_dcb *get_dcb_priv(struct nfp_net *nn)
51*9b7fe804SBin Chen {
52*9b7fe804SBin Chen 	struct nfp_dcb *dcb = &((struct nfp_app_nic_private *)nn->app_priv)->dcb;
53*9b7fe804SBin Chen 
54*9b7fe804SBin Chen 	return dcb;
55*9b7fe804SBin Chen }
56*9b7fe804SBin Chen 
nfp_tsa_ieee2nfp(u8 tsa)57*9b7fe804SBin Chen static u8 nfp_tsa_ieee2nfp(u8 tsa)
58*9b7fe804SBin Chen {
59*9b7fe804SBin Chen 	switch (tsa) {
60*9b7fe804SBin Chen 	case IEEE_8021QAZ_TSA_STRICT:
61*9b7fe804SBin Chen 		return NFP_DCB_TSA_STRICT;
62*9b7fe804SBin Chen 	case IEEE_8021QAZ_TSA_ETS:
63*9b7fe804SBin Chen 		return NFP_DCB_TSA_ETS;
64*9b7fe804SBin Chen 	default:
65*9b7fe804SBin Chen 		return NFP_DCB_TSA_VENDOR;
66*9b7fe804SBin Chen 	}
67*9b7fe804SBin Chen }
68*9b7fe804SBin Chen 
nfp_nic_dcbnl_ieee_getets(struct net_device * dev,struct ieee_ets * ets)69*9b7fe804SBin Chen static int nfp_nic_dcbnl_ieee_getets(struct net_device *dev,
70*9b7fe804SBin Chen 				     struct ieee_ets *ets)
71*9b7fe804SBin Chen {
72*9b7fe804SBin Chen 	struct nfp_net *nn = netdev_priv(dev);
73*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
74*9b7fe804SBin Chen 
75*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
76*9b7fe804SBin Chen 
77*9b7fe804SBin Chen 	for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
78*9b7fe804SBin Chen 		ets->prio_tc[i] = dcb->prio2tc[i];
79*9b7fe804SBin Chen 		ets->tc_tx_bw[i] = dcb->tc_tx_pct[i];
80*9b7fe804SBin Chen 		ets->tc_tsa[i] = dcb->tc_tsa[i];
81*9b7fe804SBin Chen 	}
82*9b7fe804SBin Chen 
83*9b7fe804SBin Chen 	return 0;
84*9b7fe804SBin Chen }
85*9b7fe804SBin Chen 
nfp_refresh_tc2idx(struct nfp_net * nn)86*9b7fe804SBin Chen static bool nfp_refresh_tc2idx(struct nfp_net *nn)
87*9b7fe804SBin Chen {
88*9b7fe804SBin Chen 	u8 tc2idx[IEEE_8021QAZ_MAX_TCS];
89*9b7fe804SBin Chen 	bool change = false;
90*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
91*9b7fe804SBin Chen 	int maxstrict = 0;
92*9b7fe804SBin Chen 
93*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
94*9b7fe804SBin Chen 
95*9b7fe804SBin Chen 	for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
96*9b7fe804SBin Chen 		tc2idx[i] = i;
97*9b7fe804SBin Chen 		if (dcb->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT)
98*9b7fe804SBin Chen 			maxstrict = i;
99*9b7fe804SBin Chen 	}
100*9b7fe804SBin Chen 
101*9b7fe804SBin Chen 	if (maxstrict > 0 && dcb->tc_tsa[0] != IEEE_8021QAZ_TSA_STRICT) {
102*9b7fe804SBin Chen 		tc2idx[0] = maxstrict;
103*9b7fe804SBin Chen 		tc2idx[maxstrict] = 0;
104*9b7fe804SBin Chen 	}
105*9b7fe804SBin Chen 
106*9b7fe804SBin Chen 	for (unsigned int j = 0; j < IEEE_8021QAZ_MAX_TCS; j++) {
107*9b7fe804SBin Chen 		if (dcb->tc2idx[j] != tc2idx[j]) {
108*9b7fe804SBin Chen 			change = true;
109*9b7fe804SBin Chen 			dcb->tc2idx[j] = tc2idx[j];
110*9b7fe804SBin Chen 		}
111*9b7fe804SBin Chen 	}
112*9b7fe804SBin Chen 
113*9b7fe804SBin Chen 	return change;
114*9b7fe804SBin Chen }
115*9b7fe804SBin Chen 
nfp_fill_maxrate(struct nfp_net * nn,u64 * max_rate_array)116*9b7fe804SBin Chen static int nfp_fill_maxrate(struct nfp_net *nn, u64 *max_rate_array)
117*9b7fe804SBin Chen {
118*9b7fe804SBin Chen 	struct nfp_app *app  = nn->app;
119*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
120*9b7fe804SBin Chen 	u32 ratembps;
121*9b7fe804SBin Chen 
122*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
123*9b7fe804SBin Chen 
124*9b7fe804SBin Chen 	for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
125*9b7fe804SBin Chen 		/* Convert bandwidth from kbps to mbps. */
126*9b7fe804SBin Chen 		ratembps = max_rate_array[i] / 1024;
127*9b7fe804SBin Chen 
128*9b7fe804SBin Chen 		/* Reject input values >= NFP_DCB_TC_RATE_MAX */
129*9b7fe804SBin Chen 		if (ratembps >= NFP_DCB_TC_RATE_MAX) {
130*9b7fe804SBin Chen 			nfp_warn(app->cpp, "ratembps(%d) must less than %d.",
131*9b7fe804SBin Chen 				 ratembps, NFP_DCB_TC_RATE_MAX);
132*9b7fe804SBin Chen 			return -EINVAL;
133*9b7fe804SBin Chen 		}
134*9b7fe804SBin Chen 		/* Input value 0 mapped to NFP_DCB_TC_RATE_MAX for firmware. */
135*9b7fe804SBin Chen 		if (ratembps == 0)
136*9b7fe804SBin Chen 			ratembps = NFP_DCB_TC_RATE_MAX;
137*9b7fe804SBin Chen 
138*9b7fe804SBin Chen 		writew((u16)ratembps, dcb->dcbcfg_tbl +
139*9b7fe804SBin Chen 		       dcb->cfg_offset + NFP_DCB_DATA_OFF_RATE + dcb->tc2idx[i] * 2);
140*9b7fe804SBin Chen 		/* for rate value from user space, need to sync to dcb structure */
141*9b7fe804SBin Chen 		if (dcb->tc_maxrate != max_rate_array)
142*9b7fe804SBin Chen 			dcb->tc_maxrate[i] = max_rate_array[i];
143*9b7fe804SBin Chen 	}
144*9b7fe804SBin Chen 
145*9b7fe804SBin Chen 	return 0;
146*9b7fe804SBin Chen }
147*9b7fe804SBin Chen 
update_dscp_maxrate(struct net_device * dev,u32 * update)148*9b7fe804SBin Chen static int update_dscp_maxrate(struct net_device *dev, u32 *update)
149*9b7fe804SBin Chen {
150*9b7fe804SBin Chen 	struct nfp_net *nn = netdev_priv(dev);
151*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
152*9b7fe804SBin Chen 	int err;
153*9b7fe804SBin Chen 
154*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
155*9b7fe804SBin Chen 
156*9b7fe804SBin Chen 	err = nfp_fill_maxrate(nn, dcb->tc_maxrate);
157*9b7fe804SBin Chen 	if (err)
158*9b7fe804SBin Chen 		return err;
159*9b7fe804SBin Chen 
160*9b7fe804SBin Chen 	*update |= NFP_DCB_MSG_MSK_RATE;
161*9b7fe804SBin Chen 
162*9b7fe804SBin Chen 	/* We only refresh dscp in dscp trust mode. */
163*9b7fe804SBin Chen 	if (dcb->dscp_cnt > 0) {
164*9b7fe804SBin Chen 		for (unsigned int i = 0; i < NFP_NET_MAX_DSCP; i++) {
165*9b7fe804SBin Chen 			writeb(dcb->tc2idx[dcb->prio2tc[dcb->dscp2prio[i]]],
166*9b7fe804SBin Chen 			       dcb->dcbcfg_tbl + dcb->cfg_offset +
167*9b7fe804SBin Chen 			       NFP_DCB_DATA_OFF_DSCP2IDX + i);
168*9b7fe804SBin Chen 		}
169*9b7fe804SBin Chen 		*update |= NFP_DCB_MSG_MSK_DSCP;
170*9b7fe804SBin Chen 	}
171*9b7fe804SBin Chen 
172*9b7fe804SBin Chen 	return 0;
173*9b7fe804SBin Chen }
174*9b7fe804SBin Chen 
nfp_nic_set_trust(struct nfp_net * nn,u32 * update)175*9b7fe804SBin Chen static void nfp_nic_set_trust(struct nfp_net *nn, u32 *update)
176*9b7fe804SBin Chen {
177*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
178*9b7fe804SBin Chen 	u8 trust;
179*9b7fe804SBin Chen 
180*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
181*9b7fe804SBin Chen 
182*9b7fe804SBin Chen 	if (dcb->trust_status != NFP_DCB_TRUST_INVALID)
183*9b7fe804SBin Chen 		return;
184*9b7fe804SBin Chen 
185*9b7fe804SBin Chen 	trust = dcb->dscp_cnt > 0 ? NFP_DCB_TRUST_DSCP : NFP_DCB_TRUST_PCP;
186*9b7fe804SBin Chen 	writeb(trust, dcb->dcbcfg_tbl + dcb->cfg_offset +
187*9b7fe804SBin Chen 	       NFP_DCB_DATA_OFF_TRUST);
188*9b7fe804SBin Chen 
189*9b7fe804SBin Chen 	dcb->trust_status = trust;
190*9b7fe804SBin Chen 	*update |= NFP_DCB_MSG_MSK_TRUST;
191*9b7fe804SBin Chen }
192*9b7fe804SBin Chen 
nfp_nic_set_enable(struct nfp_net * nn,u32 enable,u32 * update)193*9b7fe804SBin Chen static void nfp_nic_set_enable(struct nfp_net *nn, u32 enable, u32 *update)
194*9b7fe804SBin Chen {
195*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
196*9b7fe804SBin Chen 	u32 value = 0;
197*9b7fe804SBin Chen 
198*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
199*9b7fe804SBin Chen 
200*9b7fe804SBin Chen 	value = readl(dcb->dcbcfg_tbl + dcb->cfg_offset +
201*9b7fe804SBin Chen 		      NFP_DCB_DATA_OFF_ENABLE);
202*9b7fe804SBin Chen 	if (value != enable) {
203*9b7fe804SBin Chen 		writel(enable, dcb->dcbcfg_tbl + dcb->cfg_offset +
204*9b7fe804SBin Chen 		       NFP_DCB_DATA_OFF_ENABLE);
205*9b7fe804SBin Chen 		*update |= NFP_DCB_MSG_MSK_ENABLE;
206*9b7fe804SBin Chen 	}
207*9b7fe804SBin Chen }
208*9b7fe804SBin Chen 
dcb_ets_check(struct net_device * dev,struct ieee_ets * ets)209*9b7fe804SBin Chen static int dcb_ets_check(struct net_device *dev, struct ieee_ets *ets)
210*9b7fe804SBin Chen {
211*9b7fe804SBin Chen 	struct nfp_net *nn = netdev_priv(dev);
212*9b7fe804SBin Chen 	struct nfp_app *app = nn->app;
213*9b7fe804SBin Chen 	bool ets_exists = false;
214*9b7fe804SBin Chen 	int sum = 0;
215*9b7fe804SBin Chen 
216*9b7fe804SBin Chen 	for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
217*9b7fe804SBin Chen 		/* For ets mode, check bw percentage sum. */
218*9b7fe804SBin Chen 		if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) {
219*9b7fe804SBin Chen 			ets_exists = true;
220*9b7fe804SBin Chen 			sum += ets->tc_tx_bw[i];
221*9b7fe804SBin Chen 		} else if (ets->tc_tx_bw[i]) {
222*9b7fe804SBin Chen 			nfp_warn(app->cpp, "ETS BW for strict/vendor TC must be 0.");
223*9b7fe804SBin Chen 			return -EINVAL;
224*9b7fe804SBin Chen 		}
225*9b7fe804SBin Chen 	}
226*9b7fe804SBin Chen 
227*9b7fe804SBin Chen 	if (ets_exists && sum != 100) {
228*9b7fe804SBin Chen 		nfp_warn(app->cpp, "Failed to validate ETS BW: sum must be 100.");
229*9b7fe804SBin Chen 		return -EINVAL;
230*9b7fe804SBin Chen 	}
231*9b7fe804SBin Chen 
232*9b7fe804SBin Chen 	return 0;
233*9b7fe804SBin Chen }
234*9b7fe804SBin Chen 
nfp_nic_fill_ets(struct nfp_net * nn)235*9b7fe804SBin Chen static void nfp_nic_fill_ets(struct nfp_net *nn)
236*9b7fe804SBin Chen {
237*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
238*9b7fe804SBin Chen 
239*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
240*9b7fe804SBin Chen 
241*9b7fe804SBin Chen 	for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
242*9b7fe804SBin Chen 		writeb(dcb->tc2idx[dcb->prio2tc[i]],
243*9b7fe804SBin Chen 		       dcb->dcbcfg_tbl + dcb->cfg_offset + NFP_DCB_DATA_OFF_PCP2IDX + i);
244*9b7fe804SBin Chen 		writeb(dcb->tc_tx_pct[i], dcb->dcbcfg_tbl +
245*9b7fe804SBin Chen 		       dcb->cfg_offset + NFP_DCB_DATA_OFF_IDX_BW_PCT + dcb->tc2idx[i]);
246*9b7fe804SBin Chen 		writeb(nfp_tsa_ieee2nfp(dcb->tc_tsa[i]), dcb->dcbcfg_tbl +
247*9b7fe804SBin Chen 		       dcb->cfg_offset + NFP_DCB_DATA_OFF_TSA + dcb->tc2idx[i]);
248*9b7fe804SBin Chen 	}
249*9b7fe804SBin Chen }
250*9b7fe804SBin Chen 
nfp_nic_ets_init(struct nfp_net * nn,u32 * update)251*9b7fe804SBin Chen static void nfp_nic_ets_init(struct nfp_net *nn, u32 *update)
252*9b7fe804SBin Chen {
253*9b7fe804SBin Chen 	struct nfp_dcb *dcb = get_dcb_priv(nn);
254*9b7fe804SBin Chen 
255*9b7fe804SBin Chen 	if (dcb->ets_init)
256*9b7fe804SBin Chen 		return;
257*9b7fe804SBin Chen 
258*9b7fe804SBin Chen 	nfp_nic_fill_ets(nn);
259*9b7fe804SBin Chen 	dcb->ets_init = true;
260*9b7fe804SBin Chen 	*update |= NFP_DCB_MSG_MSK_TSA | NFP_DCB_MSG_MSK_PCT | NFP_DCB_MSG_MSK_PCP;
261*9b7fe804SBin Chen }
262*9b7fe804SBin Chen 
nfp_nic_dcbnl_ieee_setets(struct net_device * dev,struct ieee_ets * ets)263*9b7fe804SBin Chen static int nfp_nic_dcbnl_ieee_setets(struct net_device *dev,
264*9b7fe804SBin Chen 				     struct ieee_ets *ets)
265*9b7fe804SBin Chen {
266*9b7fe804SBin Chen 	const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE;
267*9b7fe804SBin Chen 	struct nfp_net *nn = netdev_priv(dev);
268*9b7fe804SBin Chen 	struct nfp_app *app = nn->app;
269*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
270*9b7fe804SBin Chen 	u32 update = 0;
271*9b7fe804SBin Chen 	bool change;
272*9b7fe804SBin Chen 	int err;
273*9b7fe804SBin Chen 
274*9b7fe804SBin Chen 	err = dcb_ets_check(dev, ets);
275*9b7fe804SBin Chen 	if (err)
276*9b7fe804SBin Chen 		return err;
277*9b7fe804SBin Chen 
278*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
279*9b7fe804SBin Chen 
280*9b7fe804SBin Chen 	for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
281*9b7fe804SBin Chen 		dcb->prio2tc[i] = ets->prio_tc[i];
282*9b7fe804SBin Chen 		dcb->tc_tx_pct[i] = ets->tc_tx_bw[i];
283*9b7fe804SBin Chen 		dcb->tc_tsa[i] = ets->tc_tsa[i];
284*9b7fe804SBin Chen 	}
285*9b7fe804SBin Chen 
286*9b7fe804SBin Chen 	change = nfp_refresh_tc2idx(nn);
287*9b7fe804SBin Chen 	nfp_nic_fill_ets(nn);
288*9b7fe804SBin Chen 	dcb->ets_init = true;
289*9b7fe804SBin Chen 	if (change || !dcb->rate_init) {
290*9b7fe804SBin Chen 		err = update_dscp_maxrate(dev, &update);
291*9b7fe804SBin Chen 		if (err) {
292*9b7fe804SBin Chen 			nfp_warn(app->cpp,
293*9b7fe804SBin Chen 				 "nfp dcbnl ieee setets ERROR:%d.",
294*9b7fe804SBin Chen 				 err);
295*9b7fe804SBin Chen 			return err;
296*9b7fe804SBin Chen 		}
297*9b7fe804SBin Chen 
298*9b7fe804SBin Chen 		dcb->rate_init = true;
299*9b7fe804SBin Chen 	}
300*9b7fe804SBin Chen 	nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update);
301*9b7fe804SBin Chen 	nfp_nic_set_trust(nn, &update);
302*9b7fe804SBin Chen 	err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);
303*9b7fe804SBin Chen 	if (err)
304*9b7fe804SBin Chen 		return err;
305*9b7fe804SBin Chen 
306*9b7fe804SBin Chen 	nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,
307*9b7fe804SBin Chen 		  update | NFP_DCB_MSG_MSK_TSA | NFP_DCB_MSG_MSK_PCT |
308*9b7fe804SBin Chen 		  NFP_DCB_MSG_MSK_PCP);
309*9b7fe804SBin Chen 
310*9b7fe804SBin Chen 	return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
311*9b7fe804SBin Chen }
312*9b7fe804SBin Chen 
nfp_nic_dcbnl_ieee_getmaxrate(struct net_device * dev,struct ieee_maxrate * maxrate)313*9b7fe804SBin Chen static int nfp_nic_dcbnl_ieee_getmaxrate(struct net_device *dev,
314*9b7fe804SBin Chen 					 struct ieee_maxrate *maxrate)
315*9b7fe804SBin Chen {
316*9b7fe804SBin Chen 	struct nfp_net *nn = netdev_priv(dev);
317*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
318*9b7fe804SBin Chen 
319*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
320*9b7fe804SBin Chen 
321*9b7fe804SBin Chen 	for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
322*9b7fe804SBin Chen 		maxrate->tc_maxrate[i] = dcb->tc_maxrate[i];
323*9b7fe804SBin Chen 
324*9b7fe804SBin Chen 	return 0;
325*9b7fe804SBin Chen }
326*9b7fe804SBin Chen 
nfp_nic_dcbnl_ieee_setmaxrate(struct net_device * dev,struct ieee_maxrate * maxrate)327*9b7fe804SBin Chen static int nfp_nic_dcbnl_ieee_setmaxrate(struct net_device *dev,
328*9b7fe804SBin Chen 					 struct ieee_maxrate *maxrate)
329*9b7fe804SBin Chen {
330*9b7fe804SBin Chen 	const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE;
331*9b7fe804SBin Chen 	struct nfp_net *nn = netdev_priv(dev);
332*9b7fe804SBin Chen 	struct nfp_app *app = nn->app;
333*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
334*9b7fe804SBin Chen 	u32 update = 0;
335*9b7fe804SBin Chen 	int err;
336*9b7fe804SBin Chen 
337*9b7fe804SBin Chen 	err = nfp_fill_maxrate(nn, maxrate->tc_maxrate);
338*9b7fe804SBin Chen 	if (err) {
339*9b7fe804SBin Chen 		nfp_warn(app->cpp,
340*9b7fe804SBin Chen 			 "nfp dcbnl ieee setmaxrate ERROR:%d.",
341*9b7fe804SBin Chen 			 err);
342*9b7fe804SBin Chen 		return err;
343*9b7fe804SBin Chen 	}
344*9b7fe804SBin Chen 
345*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
346*9b7fe804SBin Chen 
347*9b7fe804SBin Chen 	dcb->rate_init = true;
348*9b7fe804SBin Chen 	nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update);
349*9b7fe804SBin Chen 	nfp_nic_set_trust(nn, &update);
350*9b7fe804SBin Chen 	nfp_nic_ets_init(nn, &update);
351*9b7fe804SBin Chen 
352*9b7fe804SBin Chen 	err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);
353*9b7fe804SBin Chen 	if (err)
354*9b7fe804SBin Chen 		return err;
355*9b7fe804SBin Chen 
356*9b7fe804SBin Chen 	nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,
357*9b7fe804SBin Chen 		  update | NFP_DCB_MSG_MSK_RATE);
358*9b7fe804SBin Chen 
359*9b7fe804SBin Chen 	return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
360*9b7fe804SBin Chen }
361*9b7fe804SBin Chen 
nfp_nic_set_trust_status(struct nfp_net * nn,u8 status)362*9b7fe804SBin Chen static int nfp_nic_set_trust_status(struct nfp_net *nn, u8 status)
363*9b7fe804SBin Chen {
364*9b7fe804SBin Chen 	const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE;
365*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
366*9b7fe804SBin Chen 	u32 update = 0;
367*9b7fe804SBin Chen 	int err;
368*9b7fe804SBin Chen 
369*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
370*9b7fe804SBin Chen 	if (!dcb->rate_init) {
371*9b7fe804SBin Chen 		err = nfp_fill_maxrate(nn, dcb->tc_maxrate);
372*9b7fe804SBin Chen 		if (err)
373*9b7fe804SBin Chen 			return err;
374*9b7fe804SBin Chen 
375*9b7fe804SBin Chen 		update |= NFP_DCB_MSG_MSK_RATE;
376*9b7fe804SBin Chen 		dcb->rate_init = true;
377*9b7fe804SBin Chen 	}
378*9b7fe804SBin Chen 
379*9b7fe804SBin Chen 	err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);
380*9b7fe804SBin Chen 	if (err)
381*9b7fe804SBin Chen 		return err;
382*9b7fe804SBin Chen 
383*9b7fe804SBin Chen 	nfp_nic_ets_init(nn, &update);
384*9b7fe804SBin Chen 	writeb(status, dcb->dcbcfg_tbl + dcb->cfg_offset +
385*9b7fe804SBin Chen 	       NFP_DCB_DATA_OFF_TRUST);
386*9b7fe804SBin Chen 	nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update);
387*9b7fe804SBin Chen 	nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,
388*9b7fe804SBin Chen 		  update | NFP_DCB_MSG_MSK_TRUST);
389*9b7fe804SBin Chen 
390*9b7fe804SBin Chen 	err = nfp_net_mbox_reconfig_and_unlock(nn, cmd);
391*9b7fe804SBin Chen 	if (err)
392*9b7fe804SBin Chen 		return err;
393*9b7fe804SBin Chen 
394*9b7fe804SBin Chen 	dcb->trust_status = status;
395*9b7fe804SBin Chen 
396*9b7fe804SBin Chen 	return 0;
397*9b7fe804SBin Chen }
398*9b7fe804SBin Chen 
nfp_nic_set_dscp2prio(struct nfp_net * nn,u8 dscp,u8 prio)399*9b7fe804SBin Chen static int nfp_nic_set_dscp2prio(struct nfp_net *nn, u8 dscp, u8 prio)
400*9b7fe804SBin Chen {
401*9b7fe804SBin Chen 	const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE;
402*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
403*9b7fe804SBin Chen 	u8 idx, tc;
404*9b7fe804SBin Chen 	int err;
405*9b7fe804SBin Chen 
406*9b7fe804SBin Chen 	err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);
407*9b7fe804SBin Chen 	if (err)
408*9b7fe804SBin Chen 		return err;
409*9b7fe804SBin Chen 
410*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
411*9b7fe804SBin Chen 
412*9b7fe804SBin Chen 	tc = dcb->prio2tc[prio];
413*9b7fe804SBin Chen 	idx = dcb->tc2idx[tc];
414*9b7fe804SBin Chen 
415*9b7fe804SBin Chen 	writeb(idx, dcb->dcbcfg_tbl + dcb->cfg_offset +
416*9b7fe804SBin Chen 	       NFP_DCB_DATA_OFF_DSCP2IDX + dscp);
417*9b7fe804SBin Chen 
418*9b7fe804SBin Chen 	nn_writel(nn, nn->tlv_caps.mbox_off +
419*9b7fe804SBin Chen 		  NFP_NET_CFG_MBOX_SIMPLE_VAL, NFP_DCB_MSG_MSK_DSCP);
420*9b7fe804SBin Chen 
421*9b7fe804SBin Chen 	err = nfp_net_mbox_reconfig_and_unlock(nn, cmd);
422*9b7fe804SBin Chen 	if (err)
423*9b7fe804SBin Chen 		return err;
424*9b7fe804SBin Chen 
425*9b7fe804SBin Chen 	dcb->dscp2prio[dscp] = prio;
426*9b7fe804SBin Chen 
427*9b7fe804SBin Chen 	return 0;
428*9b7fe804SBin Chen }
429*9b7fe804SBin Chen 
nfp_nic_dcbnl_ieee_setapp(struct net_device * dev,struct dcb_app * app)430*9b7fe804SBin Chen static int nfp_nic_dcbnl_ieee_setapp(struct net_device *dev,
431*9b7fe804SBin Chen 				     struct dcb_app *app)
432*9b7fe804SBin Chen {
433*9b7fe804SBin Chen 	struct nfp_net *nn = netdev_priv(dev);
434*9b7fe804SBin Chen 	struct dcb_app old_app;
435*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
436*9b7fe804SBin Chen 	bool is_new;
437*9b7fe804SBin Chen 	int err;
438*9b7fe804SBin Chen 
439*9b7fe804SBin Chen 	if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP)
440*9b7fe804SBin Chen 		return -EINVAL;
441*9b7fe804SBin Chen 
442*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
443*9b7fe804SBin Chen 
444*9b7fe804SBin Chen 	/* Save the old entry info */
445*9b7fe804SBin Chen 	old_app.selector = IEEE_8021QAZ_APP_SEL_DSCP;
446*9b7fe804SBin Chen 	old_app.protocol = app->protocol;
447*9b7fe804SBin Chen 	old_app.priority = dcb->dscp2prio[app->protocol];
448*9b7fe804SBin Chen 
449*9b7fe804SBin Chen 	/* Check trust status */
450*9b7fe804SBin Chen 	if (!dcb->dscp_cnt) {
451*9b7fe804SBin Chen 		err = nfp_nic_set_trust_status(nn, NFP_DCB_TRUST_DSCP);
452*9b7fe804SBin Chen 		if (err)
453*9b7fe804SBin Chen 			return err;
454*9b7fe804SBin Chen 	}
455*9b7fe804SBin Chen 
456*9b7fe804SBin Chen 	/* Check if the new mapping is same as old or in init stage */
457*9b7fe804SBin Chen 	if (app->priority != old_app.priority || app->priority == 0) {
458*9b7fe804SBin Chen 		err = nfp_nic_set_dscp2prio(nn, app->protocol, app->priority);
459*9b7fe804SBin Chen 		if (err)
460*9b7fe804SBin Chen 			return err;
461*9b7fe804SBin Chen 	}
462*9b7fe804SBin Chen 
463*9b7fe804SBin Chen 	/* Delete the old entry if exists */
464*9b7fe804SBin Chen 	is_new = !!dcb_ieee_delapp(dev, &old_app);
465*9b7fe804SBin Chen 
466*9b7fe804SBin Chen 	/* Add new entry and update counter */
467*9b7fe804SBin Chen 	err = dcb_ieee_setapp(dev, app);
468*9b7fe804SBin Chen 	if (err)
469*9b7fe804SBin Chen 		return err;
470*9b7fe804SBin Chen 
471*9b7fe804SBin Chen 	if (is_new)
472*9b7fe804SBin Chen 		dcb->dscp_cnt++;
473*9b7fe804SBin Chen 
474*9b7fe804SBin Chen 	return 0;
475*9b7fe804SBin Chen }
476*9b7fe804SBin Chen 
nfp_nic_dcbnl_ieee_delapp(struct net_device * dev,struct dcb_app * app)477*9b7fe804SBin Chen static int nfp_nic_dcbnl_ieee_delapp(struct net_device *dev,
478*9b7fe804SBin Chen 				     struct dcb_app *app)
479*9b7fe804SBin Chen {
480*9b7fe804SBin Chen 	struct nfp_net *nn = netdev_priv(dev);
481*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
482*9b7fe804SBin Chen 	int err;
483*9b7fe804SBin Chen 
484*9b7fe804SBin Chen 	if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP)
485*9b7fe804SBin Chen 		return -EINVAL;
486*9b7fe804SBin Chen 
487*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
488*9b7fe804SBin Chen 
489*9b7fe804SBin Chen 	/* Check if the dcb_app param match fw */
490*9b7fe804SBin Chen 	if (app->priority != dcb->dscp2prio[app->protocol])
491*9b7fe804SBin Chen 		return -ENOENT;
492*9b7fe804SBin Chen 
493*9b7fe804SBin Chen 	/* Set fw dscp mapping to 0 */
494*9b7fe804SBin Chen 	err = nfp_nic_set_dscp2prio(nn, app->protocol, 0);
495*9b7fe804SBin Chen 	if (err)
496*9b7fe804SBin Chen 		return err;
497*9b7fe804SBin Chen 
498*9b7fe804SBin Chen 	/* Delete app from dcb list */
499*9b7fe804SBin Chen 	err = dcb_ieee_delapp(dev, app);
500*9b7fe804SBin Chen 	if (err)
501*9b7fe804SBin Chen 		return err;
502*9b7fe804SBin Chen 
503*9b7fe804SBin Chen 	/* Decrease dscp counter */
504*9b7fe804SBin Chen 	dcb->dscp_cnt--;
505*9b7fe804SBin Chen 
506*9b7fe804SBin Chen 	/* If no dscp mapping is configured, trust pcp */
507*9b7fe804SBin Chen 	if (dcb->dscp_cnt == 0)
508*9b7fe804SBin Chen 		return nfp_nic_set_trust_status(nn, NFP_DCB_TRUST_PCP);
509*9b7fe804SBin Chen 
510*9b7fe804SBin Chen 	return 0;
511*9b7fe804SBin Chen }
512*9b7fe804SBin Chen 
513*9b7fe804SBin Chen static const struct dcbnl_rtnl_ops nfp_nic_dcbnl_ops = {
514*9b7fe804SBin Chen 	/* ieee 802.1Qaz std */
515*9b7fe804SBin Chen 	.ieee_getets	= nfp_nic_dcbnl_ieee_getets,
516*9b7fe804SBin Chen 	.ieee_setets	= nfp_nic_dcbnl_ieee_setets,
517*9b7fe804SBin Chen 	.ieee_getmaxrate = nfp_nic_dcbnl_ieee_getmaxrate,
518*9b7fe804SBin Chen 	.ieee_setmaxrate = nfp_nic_dcbnl_ieee_setmaxrate,
519*9b7fe804SBin Chen 	.ieee_setapp	= nfp_nic_dcbnl_ieee_setapp,
520*9b7fe804SBin Chen 	.ieee_delapp	= nfp_nic_dcbnl_ieee_delapp,
521*9b7fe804SBin Chen };
522*9b7fe804SBin Chen 
nfp_nic_dcb_init(struct nfp_net * nn)523*9b7fe804SBin Chen int nfp_nic_dcb_init(struct nfp_net *nn)
524*9b7fe804SBin Chen {
525*9b7fe804SBin Chen 	struct nfp_app *app = nn->app;
526*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
527*9b7fe804SBin Chen 	int err;
528*9b7fe804SBin Chen 
529*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
530*9b7fe804SBin Chen 	dcb->cfg_offset = NFP_DCB_CFG_STRIDE * nn->id;
531*9b7fe804SBin Chen 	dcb->dcbcfg_tbl = nfp_pf_map_rtsym(app->pf, "net.dcbcfg_tbl",
532*9b7fe804SBin Chen 					   "_abi_dcb_cfg",
533*9b7fe804SBin Chen 					   dcb->cfg_offset, &dcb->dcbcfg_tbl_area);
534*9b7fe804SBin Chen 	if (IS_ERR(dcb->dcbcfg_tbl)) {
535*9b7fe804SBin Chen 		if (PTR_ERR(dcb->dcbcfg_tbl) != -ENOENT) {
536*9b7fe804SBin Chen 			err = PTR_ERR(dcb->dcbcfg_tbl);
537*9b7fe804SBin Chen 			dcb->dcbcfg_tbl = NULL;
538*9b7fe804SBin Chen 			nfp_err(app->cpp,
539*9b7fe804SBin Chen 				"Failed to map dcbcfg_tbl area, min_size %u.\n",
540*9b7fe804SBin Chen 				dcb->cfg_offset);
541*9b7fe804SBin Chen 			return err;
542*9b7fe804SBin Chen 		}
543*9b7fe804SBin Chen 		dcb->dcbcfg_tbl = NULL;
544*9b7fe804SBin Chen 	}
545*9b7fe804SBin Chen 
546*9b7fe804SBin Chen 	if (dcb->dcbcfg_tbl) {
547*9b7fe804SBin Chen 		for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
548*9b7fe804SBin Chen 			dcb->prio2tc[i] = i;
549*9b7fe804SBin Chen 			dcb->tc2idx[i] = i;
550*9b7fe804SBin Chen 			dcb->tc_tx_pct[i] = 0;
551*9b7fe804SBin Chen 			dcb->tc_maxrate[i] = 0;
552*9b7fe804SBin Chen 			dcb->tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR;
553*9b7fe804SBin Chen 		}
554*9b7fe804SBin Chen 		dcb->trust_status = NFP_DCB_TRUST_INVALID;
555*9b7fe804SBin Chen 		dcb->rate_init = false;
556*9b7fe804SBin Chen 		dcb->ets_init = false;
557*9b7fe804SBin Chen 
558*9b7fe804SBin Chen 		nn->dp.netdev->dcbnl_ops = &nfp_nic_dcbnl_ops;
559*9b7fe804SBin Chen 	}
560*9b7fe804SBin Chen 
561*9b7fe804SBin Chen 	return 0;
562*9b7fe804SBin Chen }
563*9b7fe804SBin Chen 
nfp_nic_dcb_clean(struct nfp_net * nn)564*9b7fe804SBin Chen void nfp_nic_dcb_clean(struct nfp_net *nn)
565*9b7fe804SBin Chen {
566*9b7fe804SBin Chen 	struct nfp_dcb *dcb;
567*9b7fe804SBin Chen 
568*9b7fe804SBin Chen 	dcb = get_dcb_priv(nn);
569*9b7fe804SBin Chen 	if (dcb->dcbcfg_tbl_area)
570*9b7fe804SBin Chen 		nfp_cpp_area_release_free(dcb->dcbcfg_tbl_area);
571*9b7fe804SBin Chen }
572