blob: 7d18504070659a49a331c820cd6dd075004cfeaa [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 07fb72fb5b3d2faeeb742ae573aa54a4a1eeee12 Mon Sep 17 00:00:00 2001
2From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
3Date: Tue, 17 Sep 2019 20:36:08 +0300
4Subject: [PATCH] dpaa2-eth: Enable Tx PFC
5
6Configure the hardware to generate PFC frames based on Rx congestion
7notifications. When a certain number of frames accumulate in the
8ingress queues corresponding to a traffic class, priority flow control
9frames are generated for that TC.
10
11Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
12---
13 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 49 ++++++++++++++++++++-
14 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 11 +++++
15 drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h | 25 +++++++++++
16 drivers/net/ethernet/freescale/dpaa2/dpni.c | 46 +++++++++++++++++++
17 drivers/net/ethernet/freescale/dpaa2/dpni.h | 56 ++++++++++++++++++++++++
18 5 files changed, 186 insertions(+), 1 deletion(-)
19
20--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
21+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
22@@ -3629,6 +3629,47 @@ static int dpaa2_eth_dcbnl_ieee_getpfc(s
23 return 0;
24 }
25
26+static inline bool is_prio_enabled(u8 pfc_en, u8 tc)
27+{
28+ return !!(pfc_en & (1 << tc));
29+}
30+
31+static int set_pfc_cn(struct dpaa2_eth_priv *priv, u8 pfc_en)
32+{
33+ struct dpni_congestion_notification_cfg cfg = {0};
34+ int i, err;
35+
36+ cfg.notification_mode = DPNI_CONG_OPT_FLOW_CONTROL;
37+ cfg.units = DPNI_CONGESTION_UNIT_FRAMES;
38+ cfg.message_iova = 0ULL;
39+ cfg.message_ctx = 0ULL;
40+
41+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
42+ if (is_prio_enabled(pfc_en, i)) {
43+ cfg.threshold_entry = DPAA2_ETH_CN_THRESH_ENTRY(priv);
44+ cfg.threshold_exit = DPAA2_ETH_CN_THRESH_EXIT(priv);
45+ } else {
46+ /* For priorities not set in the pfc_en mask, we leave
47+ * the congestion thresholds at zero, which effectively
48+ * disables generation of PFC frames for them
49+ */
50+ cfg.threshold_entry = 0;
51+ cfg.threshold_exit = 0;
52+ }
53+
54+ err = dpni_set_congestion_notification(priv->mc_io, 0,
55+ priv->mc_token,
56+ DPNI_QUEUE_RX, i, &cfg);
57+ if (err) {
58+ netdev_err(priv->net_dev,
59+ "dpni_set_congestion_notification failed\n");
60+ return err;
61+ }
62+ }
63+
64+ return 0;
65+}
66+
67 static int dpaa2_eth_dcbnl_ieee_setpfc(struct net_device *net_dev,
68 struct ieee_pfc *pfc)
69 {
70@@ -3646,7 +3687,8 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
71 /* We allow PFC configuration even if it won't have any effect until
72 * general pause frames are enabled
73 */
74- if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options))
75+ if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options) ||
76+ !dpaa2_eth_tx_pause_enabled(priv->link_state.options))
77 netdev_warn(net_dev, "Pause support must be enabled in order for PFC to work!\n");
78
79 link_cfg.rate = priv->link_state.rate;
80@@ -3661,6 +3703,11 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
81 return err;
82 }
83
84+ /* Configure congestion notifications for the enabled priorities */
85+ err = set_pfc_cn(priv, pfc->pfc_en);
86+ if (err)
87+ return err;
88+
89 memcpy(&priv->pfc, pfc, sizeof(priv->pfc));
90
91 return 0;
92--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
93+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
94@@ -65,6 +65,17 @@
95 #define DPAA2_ETH_CG_TAILDROP_THRESH(priv) \
96 (1024 * dpaa2_eth_queue_count(priv) / dpaa2_eth_tc_count(priv))
97
98+/* Congestion group notification threshold: when this many frames accumulate
99+ * on the Rx queues belonging to the same TC, the MAC is instructed to send
100+ * PFC frames for that TC.
101+ * When number of pending frames drops below exit threshold transmission of
102+ * PFC frames is stopped.
103+ */
104+#define DPAA2_ETH_CN_THRESH_ENTRY(priv) \
105+ (DPAA2_ETH_CG_TAILDROP_THRESH(priv) / 2)
106+#define DPAA2_ETH_CN_THRESH_EXIT(priv) \
107+ (DPAA2_ETH_CN_THRESH_ENTRY(priv) * 3 / 4)
108+
109 /* Maximum number of buffers that can be acquired/released through a single
110 * QBMan command
111 */
112--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
113+++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
114@@ -601,4 +601,29 @@ struct dpni_cmd_remove_qos_entry {
115 __le64 mask_iova;
116 };
117
118+#define DPNI_DEST_TYPE_SHIFT 0
119+#define DPNI_DEST_TYPE_SIZE 4
120+#define DPNI_CONG_UNITS_SHIFT 4
121+#define DPNI_CONG_UNITS_SIZE 2
122+
123+struct dpni_cmd_set_congestion_notification {
124+ /* cmd word 0 */
125+ u8 qtype;
126+ u8 tc;
127+ u8 pad[6];
128+ /* cmd word 1 */
129+ __le32 dest_id;
130+ __le16 notification_mode;
131+ u8 dest_priority;
132+ /* from LSB: dest_type: 4 units:2 */
133+ u8 type_units;
134+ /* cmd word 2 */
135+ __le64 message_iova;
136+ /* cmd word 3 */
137+ __le64 message_ctx;
138+ /* cmd word 4 */
139+ __le32 threshold_entry;
140+ __le32 threshold_exit;
141+};
142+
143 #endif /* _FSL_DPNI_CMD_H */
144--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
145+++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
146@@ -1355,6 +1355,52 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io
147 }
148
149 /**
150+ * dpni_set_congestion_notification() - Set traffic class congestion
151+ * notification configuration
152+ * @mc_io: Pointer to MC portal's I/O object
153+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
154+ * @token: Token of DPNI object
155+ * @qtype: Type of queue - Rx, Tx and Tx confirm types are supported
156+ * @tc_id: Traffic class selection (0-7)
157+ * @cfg: Congestion notification configuration
158+ *
159+ * Return: '0' on Success; error code otherwise.
160+ */
161+int dpni_set_congestion_notification(
162+ struct fsl_mc_io *mc_io,
163+ u32 cmd_flags,
164+ u16 token,
165+ enum dpni_queue_type qtype,
166+ u8 tc_id,
167+ const struct dpni_congestion_notification_cfg *cfg)
168+{
169+ struct dpni_cmd_set_congestion_notification *cmd_params;
170+ struct fsl_mc_command cmd = { 0 };
171+
172+ /* prepare command */
173+ cmd.header =
174+ mc_encode_cmd_header(DPNI_CMDID_SET_CONGESTION_NOTIFICATION,
175+ cmd_flags,
176+ token);
177+ cmd_params = (struct dpni_cmd_set_congestion_notification *)cmd.params;
178+ cmd_params->qtype = qtype;
179+ cmd_params->tc = tc_id;
180+ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
181+ cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode);
182+ cmd_params->dest_priority = cfg->dest_cfg.priority;
183+ dpni_set_field(cmd_params->type_units, DEST_TYPE,
184+ cfg->dest_cfg.dest_type);
185+ dpni_set_field(cmd_params->type_units, CONG_UNITS, cfg->units);
186+ cmd_params->message_iova = cpu_to_le64(cfg->message_iova);
187+ cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx);
188+ cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry);
189+ cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit);
190+
191+ /* send command to mc*/
192+ return mc_send_command(mc_io, &cmd);
193+}
194+
195+/**
196 * dpni_set_queue() - Set queue parameters
197 * @mc_io: Pointer to MC portal's I/O object
198 * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
199--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
200+++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
201@@ -883,6 +883,62 @@ enum dpni_congestion_point {
202 };
203
204 /**
205+ * struct dpni_dest_cfg - Structure representing DPNI destination parameters
206+ * @dest_type: Destination type
207+ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type
208+ * @priority: Priority selection within the DPIO or DPCON channel; valid
209+ * values are 0-1 or 0-7, depending on the number of priorities
210+ * in that channel; not relevant for 'DPNI_DEST_NONE' option
211+ */
212+struct dpni_dest_cfg {
213+ enum dpni_dest dest_type;
214+ int dest_id;
215+ u8 priority;
216+};
217+
218+/* DPNI congestion options */
219+
220+/**
221+ * This congestion will trigger flow control or priority flow control.
222+ * This will have effect only if flow control is enabled with
223+ * dpni_set_link_cfg().
224+ */
225+#define DPNI_CONG_OPT_FLOW_CONTROL 0x00000040
226+
227+/**
228+ * struct dpni_congestion_notification_cfg - congestion notification
229+ * configuration
230+ * @units: Units type
231+ * @threshold_entry: Above this threshold we enter a congestion state.
232+ * set it to '0' to disable it
233+ * @threshold_exit: Below this threshold we exit the congestion state.
234+ * @message_ctx: The context that will be part of the CSCN message
235+ * @message_iova: I/O virtual address (must be in DMA-able memory),
236+ * must be 16B aligned; valid only if 'DPNI_CONG_OPT_WRITE_MEM_<X>'
237+ * is contained in 'options'
238+ * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel
239+ * @notification_mode: Mask of available options; use 'DPNI_CONG_OPT_<X>' values
240+ */
241+
242+struct dpni_congestion_notification_cfg {
243+ enum dpni_congestion_unit units;
244+ u32 threshold_entry;
245+ u32 threshold_exit;
246+ u64 message_ctx;
247+ u64 message_iova;
248+ struct dpni_dest_cfg dest_cfg;
249+ u16 notification_mode;
250+};
251+
252+int dpni_set_congestion_notification(
253+ struct fsl_mc_io *mc_io,
254+ u32 cmd_flags,
255+ u16 token,
256+ enum dpni_queue_type qtype,
257+ u8 tc_id,
258+ const struct dpni_congestion_notification_cfg *cfg);
259+
260+/**
261 * struct dpni_taildrop - Structure representing the taildrop
262 * @enable: Indicates whether the taildrop is active or not.
263 * @units: Indicates the unit of THRESHOLD. Queue taildrop only supports