Linux Audio

Check our new training course

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