mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-20 22:23:27 +00:00
1b2fefb244
Refreshed patches, removed upstreamed patch: generic/pending: 001-v5.4-pinctrl-qcom-fix-wrong-write-in-update_dual_edge.patch.patch Run tested: qemu-x86-64 Build tested: x86/64, ath79/nand, imx6, sunxi/a53 Signed-off-by: Petr Štetiar <ynezz@true.cz>
264 lines
8.7 KiB
Diff
264 lines
8.7 KiB
Diff
From 07fb72fb5b3d2faeeb742ae573aa54a4a1eeee12 Mon Sep 17 00:00:00 2001
|
|
From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
|
|
Date: Tue, 17 Sep 2019 20:36:08 +0300
|
|
Subject: [PATCH] dpaa2-eth: Enable Tx PFC
|
|
|
|
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.
|
|
|
|
Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
|
|
---
|
|
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 49 ++++++++++++++++++++-
|
|
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 11 +++++
|
|
drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h | 25 +++++++++++
|
|
drivers/net/ethernet/freescale/dpaa2/dpni.c | 46 +++++++++++++++++++
|
|
drivers/net/ethernet/freescale/dpaa2/dpni.h | 56 ++++++++++++++++++++++++
|
|
5 files changed, 186 insertions(+), 1 deletion(-)
|
|
|
|
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
|
|
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
|
|
@@ -3627,6 +3627,47 @@ static int dpaa2_eth_dcbnl_ieee_getpfc(s
|
|
return 0;
|
|
}
|
|
|
|
+static inline bool is_prio_enabled(u8 pfc_en, u8 tc)
|
|
+{
|
|
+ return !!(pfc_en & (1 << tc));
|
|
+}
|
|
+
|
|
+static int set_pfc_cn(struct dpaa2_eth_priv *priv, u8 pfc_en)
|
|
+{
|
|
+ struct dpni_congestion_notification_cfg cfg = {0};
|
|
+ int i, err;
|
|
+
|
|
+ cfg.notification_mode = DPNI_CONG_OPT_FLOW_CONTROL;
|
|
+ cfg.units = DPNI_CONGESTION_UNIT_FRAMES;
|
|
+ cfg.message_iova = 0ULL;
|
|
+ cfg.message_ctx = 0ULL;
|
|
+
|
|
+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
|
|
+ if (is_prio_enabled(pfc_en, i)) {
|
|
+ cfg.threshold_entry = DPAA2_ETH_CN_THRESH_ENTRY(priv);
|
|
+ cfg.threshold_exit = DPAA2_ETH_CN_THRESH_EXIT(priv);
|
|
+ } else {
|
|
+ /* For priorities not set in the pfc_en mask, we leave
|
|
+ * the congestion thresholds at zero, which effectively
|
|
+ * disables generation of PFC frames for them
|
|
+ */
|
|
+ cfg.threshold_entry = 0;
|
|
+ cfg.threshold_exit = 0;
|
|
+ }
|
|
+
|
|
+ err = dpni_set_congestion_notification(priv->mc_io, 0,
|
|
+ priv->mc_token,
|
|
+ DPNI_QUEUE_RX, i, &cfg);
|
|
+ if (err) {
|
|
+ netdev_err(priv->net_dev,
|
|
+ "dpni_set_congestion_notification failed\n");
|
|
+ return err;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int dpaa2_eth_dcbnl_ieee_setpfc(struct net_device *net_dev,
|
|
struct ieee_pfc *pfc)
|
|
{
|
|
@@ -3644,7 +3685,8 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
|
|
/* We allow PFC configuration even if it won't have any effect until
|
|
* general pause frames are enabled
|
|
*/
|
|
- if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options))
|
|
+ if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options) ||
|
|
+ !dpaa2_eth_tx_pause_enabled(priv->link_state.options))
|
|
netdev_warn(net_dev, "Pause support must be enabled in order for PFC to work!\n");
|
|
|
|
link_cfg.rate = priv->link_state.rate;
|
|
@@ -3659,6 +3701,11 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
|
|
return err;
|
|
}
|
|
|
|
+ /* Configure congestion notifications for the enabled priorities */
|
|
+ err = set_pfc_cn(priv, pfc->pfc_en);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
memcpy(&priv->pfc, pfc, sizeof(priv->pfc));
|
|
|
|
return 0;
|
|
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
|
|
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
|
|
@@ -65,6 +65,17 @@
|
|
#define DPAA2_ETH_CG_TAILDROP_THRESH(priv) \
|
|
(1024 * dpaa2_eth_queue_count(priv) / dpaa2_eth_tc_count(priv))
|
|
|
|
+/* Congestion group notification threshold: when this many frames accumulate
|
|
+ * on the Rx queues belonging to the same TC, the MAC is instructed to send
|
|
+ * PFC frames for that TC.
|
|
+ * When number of pending frames drops below exit threshold transmission of
|
|
+ * PFC frames is stopped.
|
|
+ */
|
|
+#define DPAA2_ETH_CN_THRESH_ENTRY(priv) \
|
|
+ (DPAA2_ETH_CG_TAILDROP_THRESH(priv) / 2)
|
|
+#define DPAA2_ETH_CN_THRESH_EXIT(priv) \
|
|
+ (DPAA2_ETH_CN_THRESH_ENTRY(priv) * 3 / 4)
|
|
+
|
|
/* Maximum number of buffers that can be acquired/released through a single
|
|
* QBMan command
|
|
*/
|
|
--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
|
|
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
|
|
@@ -601,4 +601,29 @@ struct dpni_cmd_remove_qos_entry {
|
|
__le64 mask_iova;
|
|
};
|
|
|
|
+#define DPNI_DEST_TYPE_SHIFT 0
|
|
+#define DPNI_DEST_TYPE_SIZE 4
|
|
+#define DPNI_CONG_UNITS_SHIFT 4
|
|
+#define DPNI_CONG_UNITS_SIZE 2
|
|
+
|
|
+struct dpni_cmd_set_congestion_notification {
|
|
+ /* cmd word 0 */
|
|
+ u8 qtype;
|
|
+ u8 tc;
|
|
+ u8 pad[6];
|
|
+ /* cmd word 1 */
|
|
+ __le32 dest_id;
|
|
+ __le16 notification_mode;
|
|
+ u8 dest_priority;
|
|
+ /* from LSB: dest_type: 4 units:2 */
|
|
+ u8 type_units;
|
|
+ /* cmd word 2 */
|
|
+ __le64 message_iova;
|
|
+ /* cmd word 3 */
|
|
+ __le64 message_ctx;
|
|
+ /* cmd word 4 */
|
|
+ __le32 threshold_entry;
|
|
+ __le32 threshold_exit;
|
|
+};
|
|
+
|
|
#endif /* _FSL_DPNI_CMD_H */
|
|
--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
|
|
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
|
|
@@ -1355,6 +1355,52 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io
|
|
}
|
|
|
|
/**
|
|
+ * dpni_set_congestion_notification() - Set traffic class congestion
|
|
+ * notification configuration
|
|
+ * @mc_io: Pointer to MC portal's I/O object
|
|
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
|
+ * @token: Token of DPNI object
|
|
+ * @qtype: Type of queue - Rx, Tx and Tx confirm types are supported
|
|
+ * @tc_id: Traffic class selection (0-7)
|
|
+ * @cfg: Congestion notification configuration
|
|
+ *
|
|
+ * Return: '0' on Success; error code otherwise.
|
|
+ */
|
|
+int dpni_set_congestion_notification(
|
|
+ struct fsl_mc_io *mc_io,
|
|
+ u32 cmd_flags,
|
|
+ u16 token,
|
|
+ enum dpni_queue_type qtype,
|
|
+ u8 tc_id,
|
|
+ const struct dpni_congestion_notification_cfg *cfg)
|
|
+{
|
|
+ struct dpni_cmd_set_congestion_notification *cmd_params;
|
|
+ struct fsl_mc_command cmd = { 0 };
|
|
+
|
|
+ /* prepare command */
|
|
+ cmd.header =
|
|
+ mc_encode_cmd_header(DPNI_CMDID_SET_CONGESTION_NOTIFICATION,
|
|
+ cmd_flags,
|
|
+ token);
|
|
+ cmd_params = (struct dpni_cmd_set_congestion_notification *)cmd.params;
|
|
+ cmd_params->qtype = qtype;
|
|
+ cmd_params->tc = tc_id;
|
|
+ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
|
|
+ cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode);
|
|
+ cmd_params->dest_priority = cfg->dest_cfg.priority;
|
|
+ dpni_set_field(cmd_params->type_units, DEST_TYPE,
|
|
+ cfg->dest_cfg.dest_type);
|
|
+ dpni_set_field(cmd_params->type_units, CONG_UNITS, cfg->units);
|
|
+ cmd_params->message_iova = cpu_to_le64(cfg->message_iova);
|
|
+ cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx);
|
|
+ cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry);
|
|
+ cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit);
|
|
+
|
|
+ /* send command to mc*/
|
|
+ return mc_send_command(mc_io, &cmd);
|
|
+}
|
|
+
|
|
+/**
|
|
* dpni_set_queue() - Set queue parameters
|
|
* @mc_io: Pointer to MC portal's I/O object
|
|
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
|
--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
|
|
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
|
|
@@ -883,6 +883,62 @@ enum dpni_congestion_point {
|
|
};
|
|
|
|
/**
|
|
+ * struct dpni_dest_cfg - Structure representing DPNI destination parameters
|
|
+ * @dest_type: Destination type
|
|
+ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type
|
|
+ * @priority: Priority selection within the DPIO or DPCON channel; valid
|
|
+ * values are 0-1 or 0-7, depending on the number of priorities
|
|
+ * in that channel; not relevant for 'DPNI_DEST_NONE' option
|
|
+ */
|
|
+struct dpni_dest_cfg {
|
|
+ enum dpni_dest dest_type;
|
|
+ int dest_id;
|
|
+ u8 priority;
|
|
+};
|
|
+
|
|
+/* DPNI congestion options */
|
|
+
|
|
+/**
|
|
+ * This congestion will trigger flow control or priority flow control.
|
|
+ * This will have effect only if flow control is enabled with
|
|
+ * dpni_set_link_cfg().
|
|
+ */
|
|
+#define DPNI_CONG_OPT_FLOW_CONTROL 0x00000040
|
|
+
|
|
+/**
|
|
+ * struct dpni_congestion_notification_cfg - congestion notification
|
|
+ * configuration
|
|
+ * @units: Units type
|
|
+ * @threshold_entry: Above this threshold we enter a congestion state.
|
|
+ * set it to '0' to disable it
|
|
+ * @threshold_exit: Below this threshold we exit the congestion state.
|
|
+ * @message_ctx: The context that will be part of the CSCN message
|
|
+ * @message_iova: I/O virtual address (must be in DMA-able memory),
|
|
+ * must be 16B aligned; valid only if 'DPNI_CONG_OPT_WRITE_MEM_<X>'
|
|
+ * is contained in 'options'
|
|
+ * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel
|
|
+ * @notification_mode: Mask of available options; use 'DPNI_CONG_OPT_<X>' values
|
|
+ */
|
|
+
|
|
+struct dpni_congestion_notification_cfg {
|
|
+ enum dpni_congestion_unit units;
|
|
+ u32 threshold_entry;
|
|
+ u32 threshold_exit;
|
|
+ u64 message_ctx;
|
|
+ u64 message_iova;
|
|
+ struct dpni_dest_cfg dest_cfg;
|
|
+ u16 notification_mode;
|
|
+};
|
|
+
|
|
+int dpni_set_congestion_notification(
|
|
+ struct fsl_mc_io *mc_io,
|
|
+ u32 cmd_flags,
|
|
+ u16 token,
|
|
+ enum dpni_queue_type qtype,
|
|
+ u8 tc_id,
|
|
+ const struct dpni_congestion_notification_cfg *cfg);
|
|
+
|
|
+/**
|
|
* struct dpni_taildrop - Structure representing the taildrop
|
|
* @enable: Indicates whether the taildrop is active or not.
|
|
* @units: Indicates the unit of THRESHOLD. Queue taildrop only supports
|