| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From 07fb72fb5b3d2faeeb742ae573aa54a4a1eeee12 Mon Sep 17 00:00:00 2001 |
| 2 | From: Ioana Radulescu <ruxandra.radulescu@nxp.com> |
| 3 | Date: Tue, 17 Sep 2019 20:36:08 +0300 |
| 4 | Subject: [PATCH] dpaa2-eth: Enable Tx PFC |
| 5 | |
| 6 | Configure the hardware to generate PFC frames based on Rx congestion |
| 7 | notifications. When a certain number of frames accumulate in the |
| 8 | ingress queues corresponding to a traffic class, priority flow control |
| 9 | frames are generated for that TC. |
| 10 | |
| 11 | Signed-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 |