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(val: (u16)ratembps, addr: 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, max_rate_array: 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(val: dcb->tc2idx[dcb->prio2tc[dcb->dscp2prio[i]]],
166 addr: 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(val: trust, addr: 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(addr: dcb->dcbcfg_tbl + dcb->cfg_offset +
201 NFP_DCB_DATA_OFF_ENABLE);
202 if (value != enable) {
203 writel(val: enable, addr: 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(val: dcb->tc2idx[dcb->prio2tc[i]],
243 addr: dcb->dcbcfg_tbl + dcb->cfg_offset + NFP_DCB_DATA_OFF_PCP2IDX + i);
244 writeb(val: dcb->tc_tx_pct[i], addr: dcb->dcbcfg_tbl +
245 dcb->cfg_offset + NFP_DCB_DATA_OFF_IDX_BW_PCT + dcb->tc2idx[i]);
246 writeb(val: nfp_tsa_ieee2nfp(tsa: dcb->tc_tsa[i]), addr: 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: &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: &update);
301 nfp_nic_set_trust(nn, update: &update);
302 err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);
303 if (err)
304 return err;
305
306 nn_writel(nn, off: nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,
307 val: 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, mbox_cmd: 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, max_rate_array: 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: &update);
349 nfp_nic_set_trust(nn, update: &update);
350 nfp_nic_ets_init(nn, update: &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, off: nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,
357 val: update | NFP_DCB_MSG_MSK_RATE);
358
359 return nfp_net_mbox_reconfig_and_unlock(nn, mbox_cmd: 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, max_rate_array: 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: &update);
384 writeb(val: status, addr: dcb->dcbcfg_tbl + dcb->cfg_offset +
385 NFP_DCB_DATA_OFF_TRUST);
386 nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, update: &update);
387 nn_writel(nn, off: nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,
388 val: update | NFP_DCB_MSG_MSK_TRUST);
389
390 err = nfp_net_mbox_reconfig_and_unlock(nn, mbox_cmd: 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(val: idx, addr: dcb->dcbcfg_tbl + dcb->cfg_offset +
416 NFP_DCB_DATA_OFF_DSCP2IDX + dscp);
417
418 nn_writel(nn, off: 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, mbox_cmd: 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, dscp: app->protocol, prio: 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, dscp: app->protocol, prio: 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(pf: app->pf, name: "net.dcbcfg_tbl",
532 sym_fmt: "_abi_dcb_cfg",
533 min_size: dcb->cfg_offset, area: &dcb->dcbcfg_tbl_area);
534 if (IS_ERR(ptr: dcb->dcbcfg_tbl)) {
535 if (PTR_ERR(ptr: dcb->dcbcfg_tbl) != -ENOENT) {
536 err = PTR_ERR(ptr: 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(area: dcb->dcbcfg_tbl_area);
571}
572

source code of linux/drivers/net/ethernet/netronome/nfp/nic/dcb.c