1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2023 Corigine, Inc. */
4 #include <linux/device.h>
5 #include <linux/netdevice.h>
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"
17 #define NFP_DCB_TRUST_PCP 1
18 #define NFP_DCB_TRUST_DSCP 2
19 #define NFP_DCB_TRUST_INVALID 0xff
21 #define NFP_DCB_TSA_VENDOR 1
22 #define NFP_DCB_TSA_STRICT 2
23 #define NFP_DCB_TSA_ETS 3
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)
30 #define NFP_DCB_UPDATE_MSK_SZ 4
31 #define NFP_DCB_TC_RATE_MAX 0xffff
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
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)
50 static struct nfp_dcb
*get_dcb_priv(struct nfp_net
*nn
)
52 struct nfp_dcb
*dcb
= &((struct nfp_app_nic_private
*)nn
->app_priv
)->dcb
;
57 static u8
nfp_tsa_ieee2nfp(u8 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
;
65 return NFP_DCB_TSA_VENDOR
;
69 static int nfp_nic_dcbnl_ieee_getets(struct net_device
*dev
,
72 struct nfp_net
*nn
= netdev_priv(dev
);
75 dcb
= get_dcb_priv(nn
);
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
];
86 static bool nfp_refresh_tc2idx(struct nfp_net
*nn
)
88 u8 tc2idx
[IEEE_8021QAZ_MAX_TCS
];
93 dcb
= get_dcb_priv(nn
);
95 for (unsigned int i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++) {
97 if (dcb
->tc_tsa
[i
] == IEEE_8021QAZ_TSA_STRICT
)
101 if (maxstrict
> 0 && dcb
->tc_tsa
[0] != IEEE_8021QAZ_TSA_STRICT
) {
102 tc2idx
[0] = maxstrict
;
103 tc2idx
[maxstrict
] = 0;
106 for (unsigned int j
= 0; j
< IEEE_8021QAZ_MAX_TCS
; j
++) {
107 if (dcb
->tc2idx
[j
] != tc2idx
[j
]) {
109 dcb
->tc2idx
[j
] = tc2idx
[j
];
116 static int nfp_fill_maxrate(struct nfp_net
*nn
, u64
*max_rate_array
)
118 struct nfp_app
*app
= nn
->app
;
122 dcb
= get_dcb_priv(nn
);
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;
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
);
134 /* Input value 0 mapped to NFP_DCB_TC_RATE_MAX for firmware. */
136 ratembps
= NFP_DCB_TC_RATE_MAX
;
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
];
148 static int update_dscp_maxrate(struct net_device
*dev
, u32
*update
)
150 struct nfp_net
*nn
= netdev_priv(dev
);
154 dcb
= get_dcb_priv(nn
);
156 err
= nfp_fill_maxrate(nn
, dcb
->tc_maxrate
);
160 *update
|= NFP_DCB_MSG_MSK_RATE
;
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
);
169 *update
|= NFP_DCB_MSG_MSK_DSCP
;
175 static void nfp_nic_set_trust(struct nfp_net
*nn
, u32
*update
)
180 dcb
= get_dcb_priv(nn
);
182 if (dcb
->trust_status
!= NFP_DCB_TRUST_INVALID
)
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
);
189 dcb
->trust_status
= trust
;
190 *update
|= NFP_DCB_MSG_MSK_TRUST
;
193 static void nfp_nic_set_enable(struct nfp_net
*nn
, u32 enable
, u32
*update
)
198 dcb
= get_dcb_priv(nn
);
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
;
209 static int dcb_ets_check(struct net_device
*dev
, struct ieee_ets
*ets
)
211 struct nfp_net
*nn
= netdev_priv(dev
);
212 struct nfp_app
*app
= nn
->app
;
213 bool ets_exists
= false;
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
) {
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.");
227 if (ets_exists
&& sum
!= 100) {
228 nfp_warn(app
->cpp
, "Failed to validate ETS BW: sum must be 100.");
235 static void nfp_nic_fill_ets(struct nfp_net
*nn
)
239 dcb
= get_dcb_priv(nn
);
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
]);
251 static void nfp_nic_ets_init(struct nfp_net
*nn
, u32
*update
)
253 struct nfp_dcb
*dcb
= get_dcb_priv(nn
);
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
;
263 static int nfp_nic_dcbnl_ieee_setets(struct net_device
*dev
,
264 struct ieee_ets
*ets
)
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
;
274 err
= dcb_ets_check(dev
, ets
);
278 dcb
= get_dcb_priv(nn
);
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
];
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
);
293 "nfp dcbnl ieee setets ERROR:%d.",
298 dcb
->rate_init
= true;
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
);
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
);
310 return nfp_net_mbox_reconfig_and_unlock(nn
, cmd
);
313 static int nfp_nic_dcbnl_ieee_getmaxrate(struct net_device
*dev
,
314 struct ieee_maxrate
*maxrate
)
316 struct nfp_net
*nn
= netdev_priv(dev
);
319 dcb
= get_dcb_priv(nn
);
321 for (unsigned int i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++)
322 maxrate
->tc_maxrate
[i
] = dcb
->tc_maxrate
[i
];
327 static int nfp_nic_dcbnl_ieee_setmaxrate(struct net_device
*dev
,
328 struct ieee_maxrate
*maxrate
)
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
;
337 err
= nfp_fill_maxrate(nn
, maxrate
->tc_maxrate
);
340 "nfp dcbnl ieee setmaxrate ERROR:%d.",
345 dcb
= get_dcb_priv(nn
);
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
);
352 err
= nfp_net_mbox_lock(nn
, NFP_DCB_UPDATE_MSK_SZ
);
356 nn_writel(nn
, nn
->tlv_caps
.mbox_off
+ NFP_NET_CFG_MBOX_SIMPLE_VAL
,
357 update
| NFP_DCB_MSG_MSK_RATE
);
359 return nfp_net_mbox_reconfig_and_unlock(nn
, cmd
);
362 static int nfp_nic_set_trust_status(struct nfp_net
*nn
, u8 status
)
364 const u32 cmd
= NFP_NET_CFG_MBOX_CMD_DCB_UPDATE
;
369 dcb
= get_dcb_priv(nn
);
370 if (!dcb
->rate_init
) {
371 err
= nfp_fill_maxrate(nn
, dcb
->tc_maxrate
);
375 update
|= NFP_DCB_MSG_MSK_RATE
;
376 dcb
->rate_init
= true;
379 err
= nfp_net_mbox_lock(nn
, NFP_DCB_UPDATE_MSK_SZ
);
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
);
390 err
= nfp_net_mbox_reconfig_and_unlock(nn
, cmd
);
394 dcb
->trust_status
= status
;
399 static int nfp_nic_set_dscp2prio(struct nfp_net
*nn
, u8 dscp
, u8 prio
)
401 const u32 cmd
= NFP_NET_CFG_MBOX_CMD_DCB_UPDATE
;
406 err
= nfp_net_mbox_lock(nn
, NFP_DCB_UPDATE_MSK_SZ
);
410 dcb
= get_dcb_priv(nn
);
412 tc
= dcb
->prio2tc
[prio
];
413 idx
= dcb
->tc2idx
[tc
];
415 writeb(idx
, dcb
->dcbcfg_tbl
+ dcb
->cfg_offset
+
416 NFP_DCB_DATA_OFF_DSCP2IDX
+ dscp
);
418 nn_writel(nn
, nn
->tlv_caps
.mbox_off
+
419 NFP_NET_CFG_MBOX_SIMPLE_VAL
, NFP_DCB_MSG_MSK_DSCP
);
421 err
= nfp_net_mbox_reconfig_and_unlock(nn
, cmd
);
425 dcb
->dscp2prio
[dscp
] = prio
;
430 static int nfp_nic_dcbnl_ieee_setapp(struct net_device
*dev
,
433 struct nfp_net
*nn
= netdev_priv(dev
);
434 struct dcb_app old_app
;
439 if (app
->selector
!= IEEE_8021QAZ_APP_SEL_DSCP
)
442 dcb
= get_dcb_priv(nn
);
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
];
449 /* Check trust status */
450 if (!dcb
->dscp_cnt
) {
451 err
= nfp_nic_set_trust_status(nn
, NFP_DCB_TRUST_DSCP
);
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
);
463 /* Delete the old entry if exists */
464 is_new
= !!dcb_ieee_delapp(dev
, &old_app
);
466 /* Add new entry and update counter */
467 err
= dcb_ieee_setapp(dev
, app
);
477 static int nfp_nic_dcbnl_ieee_delapp(struct net_device
*dev
,
480 struct nfp_net
*nn
= netdev_priv(dev
);
484 if (app
->selector
!= IEEE_8021QAZ_APP_SEL_DSCP
)
487 dcb
= get_dcb_priv(nn
);
489 /* Check if the dcb_app param match fw */
490 if (app
->priority
!= dcb
->dscp2prio
[app
->protocol
])
493 /* Set fw dscp mapping to 0 */
494 err
= nfp_nic_set_dscp2prio(nn
, app
->protocol
, 0);
498 /* Delete app from dcb list */
499 err
= dcb_ieee_delapp(dev
, app
);
503 /* Decrease dscp counter */
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
);
513 static 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
,
523 int nfp_nic_dcb_init(struct nfp_net
*nn
)
525 struct nfp_app
*app
= nn
->app
;
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",
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
;
539 "Failed to map dcbcfg_tbl area, min_size %u.\n",
543 dcb
->dcbcfg_tbl
= NULL
;
546 if (dcb
->dcbcfg_tbl
) {
547 for (unsigned int i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++) {
550 dcb
->tc_tx_pct
[i
] = 0;
551 dcb
->tc_maxrate
[i
] = 0;
552 dcb
->tc_tsa
[i
] = IEEE_8021QAZ_TSA_VENDOR
;
554 dcb
->trust_status
= NFP_DCB_TRUST_INVALID
;
555 dcb
->rate_init
= false;
556 dcb
->ets_init
= false;
558 nn
->dp
.netdev
->dcbnl_ops
= &nfp_nic_dcbnl_ops
;
564 void nfp_nic_dcb_clean(struct nfp_net
*nn
)
568 dcb
= get_dcb_priv(nn
);
569 if (dcb
->dcbcfg_tbl_area
)
570 nfp_cpp_area_release_free(dcb
->dcbcfg_tbl_area
);