Skip to content

Commit f395b69

Browse files
IoanaCiorneidavem330
authored andcommitted
dpaa2-eth: Add PFC support through DCB ops
Add support in dpaa2-eth for PFC (Priority Flow Control) through the DCB ops. Instruct the hardware to respond to received PFC frames. Current firmware doesn't allow us to selectively enable PFC on the Rx side for some priorities only, so we will react to all incoming PFC frames (and stop transmitting on the traffic classes specified in the frame). Also, configure the hardware to generate PFC frames based on Rx congestion notifications. When a certain number of frames accumulate in the ingress queues corresponding to a traffic class, priority flow control frames are generated for that TC. The number of PFC traffic classes available can be queried through lldptool. Also, which of those traffic classes have PFC enabled is also controlled through the same dcbnl_rtnl_ops callbacks. Signed-off-by: Ioana Ciornei <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3f8b826 commit f395b69

File tree

8 files changed

+316
-0
lines changed

8 files changed

+316
-0
lines changed

drivers/net/ethernet/freescale/dpaa2/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ config FSL_DPAA2_ETH
99
The driver manages network objects discovered on the Freescale
1010
MC bus.
1111

12+
if FSL_DPAA2_ETH
13+
config FSL_DPAA2_ETH_DCB
14+
bool "Data Center Bridging (DCB) Support"
15+
default n
16+
depends on DCB
17+
help
18+
Enable Priority-Based Flow Control (PFC) support for DPAA2 Ethernet
19+
devices.
20+
endif
21+
1222
config FSL_DPAA2_PTP_CLOCK
1323
tristate "Freescale DPAA2 PTP Clock"
1424
depends on FSL_DPAA2_ETH && PTP_1588_CLOCK_QORIQ

drivers/net/ethernet/freescale/dpaa2/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o
77
obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o
88

99
fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o
10+
fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_DCB} += dpaa2-eth-dcb.o
1011
fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o
1112
fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o
1213

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2+
/* Copyright 2020 NXP */
3+
4+
#include "dpaa2-eth.h"
5+
6+
static int dpaa2_eth_dcbnl_ieee_getpfc(struct net_device *net_dev,
7+
struct ieee_pfc *pfc)
8+
{
9+
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
10+
11+
if (!(priv->link_state.options & DPNI_LINK_OPT_PFC_PAUSE))
12+
return 0;
13+
14+
memcpy(pfc, &priv->pfc, sizeof(priv->pfc));
15+
pfc->pfc_cap = dpaa2_eth_tc_count(priv);
16+
17+
return 0;
18+
}
19+
20+
static inline bool is_prio_enabled(u8 pfc_en, u8 tc)
21+
{
22+
return !!(pfc_en & (1 << tc));
23+
}
24+
25+
static int set_pfc_cn(struct dpaa2_eth_priv *priv, u8 pfc_en)
26+
{
27+
struct dpni_congestion_notification_cfg cfg = {0};
28+
int i, err;
29+
30+
cfg.notification_mode = DPNI_CONG_OPT_FLOW_CONTROL;
31+
cfg.units = DPNI_CONGESTION_UNIT_FRAMES;
32+
cfg.message_iova = 0ULL;
33+
cfg.message_ctx = 0ULL;
34+
35+
for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
36+
if (is_prio_enabled(pfc_en, i)) {
37+
cfg.threshold_entry = DPAA2_ETH_CN_THRESH_ENTRY(priv);
38+
cfg.threshold_exit = DPAA2_ETH_CN_THRESH_EXIT(priv);
39+
} else {
40+
/* For priorities not set in the pfc_en mask, we leave
41+
* the congestion thresholds at zero, which effectively
42+
* disables generation of PFC frames for them
43+
*/
44+
cfg.threshold_entry = 0;
45+
cfg.threshold_exit = 0;
46+
}
47+
48+
err = dpni_set_congestion_notification(priv->mc_io, 0,
49+
priv->mc_token,
50+
DPNI_QUEUE_RX, i, &cfg);
51+
if (err) {
52+
netdev_err(priv->net_dev,
53+
"dpni_set_congestion_notification failed\n");
54+
return err;
55+
}
56+
}
57+
58+
return 0;
59+
}
60+
61+
static int dpaa2_eth_dcbnl_ieee_setpfc(struct net_device *net_dev,
62+
struct ieee_pfc *pfc)
63+
{
64+
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
65+
struct dpni_link_cfg link_cfg = {0};
66+
int err;
67+
68+
if (pfc->mbc || pfc->delay)
69+
return -EOPNOTSUPP;
70+
71+
/* If same PFC enabled mask, nothing to do */
72+
if (priv->pfc.pfc_en == pfc->pfc_en)
73+
return 0;
74+
75+
/* We allow PFC configuration even if it won't have any effect until
76+
* general pause frames are enabled
77+
*/
78+
if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options) ||
79+
!dpaa2_eth_tx_pause_enabled(priv->link_state.options))
80+
netdev_warn(net_dev, "Pause support must be enabled in order for PFC to work!\n");
81+
82+
link_cfg.rate = priv->link_state.rate;
83+
link_cfg.options = priv->link_state.options;
84+
if (pfc->pfc_en)
85+
link_cfg.options |= DPNI_LINK_OPT_PFC_PAUSE;
86+
else
87+
link_cfg.options &= ~DPNI_LINK_OPT_PFC_PAUSE;
88+
err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &link_cfg);
89+
if (err) {
90+
netdev_err(net_dev, "dpni_set_link_cfg failed\n");
91+
return err;
92+
}
93+
94+
/* Configure congestion notifications for the enabled priorities */
95+
err = set_pfc_cn(priv, pfc->pfc_en);
96+
if (err)
97+
return err;
98+
99+
memcpy(&priv->pfc, pfc, sizeof(priv->pfc));
100+
101+
return 0;
102+
}
103+
104+
static u8 dpaa2_eth_dcbnl_getdcbx(struct net_device *net_dev)
105+
{
106+
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
107+
108+
return priv->dcbx_mode;
109+
}
110+
111+
static u8 dpaa2_eth_dcbnl_setdcbx(struct net_device *net_dev, u8 mode)
112+
{
113+
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
114+
115+
return (mode != (priv->dcbx_mode)) ? 1 : 0;
116+
}
117+
118+
static u8 dpaa2_eth_dcbnl_getcap(struct net_device *net_dev, int capid, u8 *cap)
119+
{
120+
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
121+
122+
switch (capid) {
123+
case DCB_CAP_ATTR_PFC:
124+
*cap = true;
125+
break;
126+
case DCB_CAP_ATTR_PFC_TCS:
127+
*cap = 1 << (dpaa2_eth_tc_count(priv) - 1);
128+
break;
129+
case DCB_CAP_ATTR_DCBX:
130+
*cap = priv->dcbx_mode;
131+
break;
132+
default:
133+
*cap = false;
134+
break;
135+
}
136+
137+
return 0;
138+
}
139+
140+
const struct dcbnl_rtnl_ops dpaa2_eth_dcbnl_ops = {
141+
.ieee_getpfc = dpaa2_eth_dcbnl_ieee_getpfc,
142+
.ieee_setpfc = dpaa2_eth_dcbnl_ieee_setpfc,
143+
.getdcbx = dpaa2_eth_dcbnl_getdcbx,
144+
.setdcbx = dpaa2_eth_dcbnl_setdcbx,
145+
.getcap = dpaa2_eth_dcbnl_getcap,
146+
};

drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3844,6 +3844,15 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
38443844
if (err)
38453845
goto err_alloc_rings;
38463846

3847+
#ifdef CONFIG_FSL_DPAA2_ETH_DCB
3848+
if (dpaa2_eth_has_pause_support(priv) && priv->vlan_cls_enabled) {
3849+
priv->dcbx_mode = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
3850+
net_dev->dcbnl_ops = &dpaa2_eth_dcbnl_ops;
3851+
} else {
3852+
dev_dbg(dev, "PFC not supported\n");
3853+
}
3854+
#endif
3855+
38473856
err = setup_irqs(dpni_dev);
38483857
if (err) {
38493858
netdev_warn(net_dev, "Failed to set link interrupt, fall back to polling\n");

drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef __DPAA2_ETH_H
77
#define __DPAA2_ETH_H
88

9+
#include <linux/dcbnl.h>
910
#include <linux/netdevice.h>
1011
#include <linux/if_vlan.h>
1112
#include <linux/fsl/mc.h>
@@ -65,6 +66,17 @@
6566
#define DPAA2_ETH_CG_TAILDROP_THRESH(priv) \
6667
(1024 * dpaa2_eth_queue_count(priv) / dpaa2_eth_tc_count(priv))
6768

69+
/* Congestion group notification threshold: when this many frames accumulate
70+
* on the Rx queues belonging to the same TC, the MAC is instructed to send
71+
* PFC frames for that TC.
72+
* When number of pending frames drops below exit threshold transmission of
73+
* PFC frames is stopped.
74+
*/
75+
#define DPAA2_ETH_CN_THRESH_ENTRY(priv) \
76+
(DPAA2_ETH_CG_TAILDROP_THRESH(priv) / 2)
77+
#define DPAA2_ETH_CN_THRESH_EXIT(priv) \
78+
(DPAA2_ETH_CN_THRESH_ENTRY(priv) * 3 / 4)
79+
6880
/* Maximum number of buffers that can be acquired/released through a single
6981
* QBMan command
7082
*/
@@ -436,6 +448,10 @@ struct dpaa2_eth_priv {
436448
struct dpaa2_eth_cls_rule *cls_rules;
437449
u8 rx_cls_enabled;
438450
u8 vlan_cls_enabled;
451+
#ifdef CONFIG_FSL_DPAA2_ETH_DCB
452+
u8 dcbx_mode;
453+
struct ieee_pfc pfc;
454+
#endif
439455
struct bpf_prog *xdp_prog;
440456
#ifdef CONFIG_DEBUG_FS
441457
struct dpaa2_debugfs dbg;
@@ -568,4 +584,6 @@ int dpaa2_eth_cls_key_size(u64 key);
568584
int dpaa2_eth_cls_fld_off(int prot, int field);
569585
void dpaa2_eth_cls_trim_rule(void *key_mem, u64 fields);
570586

587+
extern const struct dcbnl_rtnl_ops dpaa2_eth_dcbnl_ops;
588+
571589
#endif /* __DPAA2_H */

drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,4 +601,29 @@ struct dpni_cmd_remove_qos_entry {
601601
__le64 mask_iova;
602602
};
603603

604+
#define DPNI_DEST_TYPE_SHIFT 0
605+
#define DPNI_DEST_TYPE_SIZE 4
606+
#define DPNI_CONG_UNITS_SHIFT 4
607+
#define DPNI_CONG_UNITS_SIZE 2
608+
609+
struct dpni_cmd_set_congestion_notification {
610+
/* cmd word 0 */
611+
u8 qtype;
612+
u8 tc;
613+
u8 pad[6];
614+
/* cmd word 1 */
615+
__le32 dest_id;
616+
__le16 notification_mode;
617+
u8 dest_priority;
618+
/* from LSB: dest_type: 4 units:2 */
619+
u8 type_units;
620+
/* cmd word 2 */
621+
__le64 message_iova;
622+
/* cmd word 3 */
623+
__le64 message_ctx;
624+
/* cmd word 4 */
625+
__le32 threshold_entry;
626+
__le32 threshold_exit;
627+
};
628+
604629
#endif /* _FSL_DPNI_CMD_H */

drivers/net/ethernet/freescale/dpaa2/dpni.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,52 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io,
13541354
return mc_send_command(mc_io, &cmd);
13551355
}
13561356

1357+
/**
1358+
* dpni_set_congestion_notification() - Set traffic class congestion
1359+
* notification configuration
1360+
* @mc_io: Pointer to MC portal's I/O object
1361+
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1362+
* @token: Token of DPNI object
1363+
* @qtype: Type of queue - Rx, Tx and Tx confirm types are supported
1364+
* @tc_id: Traffic class selection (0-7)
1365+
* @cfg: Congestion notification configuration
1366+
*
1367+
* Return: '0' on Success; error code otherwise.
1368+
*/
1369+
int dpni_set_congestion_notification(
1370+
struct fsl_mc_io *mc_io,
1371+
u32 cmd_flags,
1372+
u16 token,
1373+
enum dpni_queue_type qtype,
1374+
u8 tc_id,
1375+
const struct dpni_congestion_notification_cfg *cfg)
1376+
{
1377+
struct dpni_cmd_set_congestion_notification *cmd_params;
1378+
struct fsl_mc_command cmd = { 0 };
1379+
1380+
/* prepare command */
1381+
cmd.header =
1382+
mc_encode_cmd_header(DPNI_CMDID_SET_CONGESTION_NOTIFICATION,
1383+
cmd_flags,
1384+
token);
1385+
cmd_params = (struct dpni_cmd_set_congestion_notification *)cmd.params;
1386+
cmd_params->qtype = qtype;
1387+
cmd_params->tc = tc_id;
1388+
cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
1389+
cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode);
1390+
cmd_params->dest_priority = cfg->dest_cfg.priority;
1391+
dpni_set_field(cmd_params->type_units, DEST_TYPE,
1392+
cfg->dest_cfg.dest_type);
1393+
dpni_set_field(cmd_params->type_units, CONG_UNITS, cfg->units);
1394+
cmd_params->message_iova = cpu_to_le64(cfg->message_iova);
1395+
cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx);
1396+
cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry);
1397+
cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit);
1398+
1399+
/* send command to mc*/
1400+
return mc_send_command(mc_io, &cmd);
1401+
}
1402+
13571403
/**
13581404
* dpni_set_queue() - Set queue parameters
13591405
* @mc_io: Pointer to MC portal's I/O object

drivers/net/ethernet/freescale/dpaa2/dpni.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
513513
*/
514514
#define DPNI_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL
515515

516+
/**
517+
* Enable priority flow control pause frames
518+
*/
519+
#define DPNI_LINK_OPT_PFC_PAUSE 0x0000000000000010ULL
520+
516521
/**
517522
* struct - Structure representing DPNI link configuration
518523
* @rate: Rate
@@ -877,6 +882,62 @@ enum dpni_congestion_point {
877882
DPNI_CP_GROUP,
878883
};
879884

885+
/**
886+
* struct dpni_dest_cfg - Structure representing DPNI destination parameters
887+
* @dest_type: Destination type
888+
* @dest_id: Either DPIO ID or DPCON ID, depending on the destination type
889+
* @priority: Priority selection within the DPIO or DPCON channel; valid
890+
* values are 0-1 or 0-7, depending on the number of priorities
891+
* in that channel; not relevant for 'DPNI_DEST_NONE' option
892+
*/
893+
struct dpni_dest_cfg {
894+
enum dpni_dest dest_type;
895+
int dest_id;
896+
u8 priority;
897+
};
898+
899+
/* DPNI congestion options */
900+
901+
/**
902+
* This congestion will trigger flow control or priority flow control.
903+
* This will have effect only if flow control is enabled with
904+
* dpni_set_link_cfg().
905+
*/
906+
#define DPNI_CONG_OPT_FLOW_CONTROL 0x00000040
907+
908+
/**
909+
* struct dpni_congestion_notification_cfg - congestion notification
910+
* configuration
911+
* @units: Units type
912+
* @threshold_entry: Above this threshold we enter a congestion state.
913+
* set it to '0' to disable it
914+
* @threshold_exit: Below this threshold we exit the congestion state.
915+
* @message_ctx: The context that will be part of the CSCN message
916+
* @message_iova: I/O virtual address (must be in DMA-able memory),
917+
* must be 16B aligned; valid only if 'DPNI_CONG_OPT_WRITE_MEM_<X>'
918+
* is contained in 'options'
919+
* @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel
920+
* @notification_mode: Mask of available options; use 'DPNI_CONG_OPT_<X>' values
921+
*/
922+
923+
struct dpni_congestion_notification_cfg {
924+
enum dpni_congestion_unit units;
925+
u32 threshold_entry;
926+
u32 threshold_exit;
927+
u64 message_ctx;
928+
u64 message_iova;
929+
struct dpni_dest_cfg dest_cfg;
930+
u16 notification_mode;
931+
};
932+
933+
int dpni_set_congestion_notification(
934+
struct fsl_mc_io *mc_io,
935+
u32 cmd_flags,
936+
u16 token,
937+
enum dpni_queue_type qtype,
938+
u8 tc_id,
939+
const struct dpni_congestion_notification_cfg *cfg);
940+
880941
/**
881942
* struct dpni_taildrop - Structure representing the taildrop
882943
* @enable: Indicates whether the taildrop is active or not.

0 commit comments

Comments
 (0)