Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'mlx5-minimum-inline-header-mode'

Saeed Mahameed says:

====================
Mellanox 100G mlx5 minimum inline header mode

This small series from Hadar adds the support for minimum inline header mode query
in mlx5e NIC driver.

Today on TX the driver copies to the HW descriptor only up to L2 header which is the default
required mode and sufficient for today's needs.

The header in the HW descriptor is used for HW loopback steering decision, without it packets
will go directly to the wire with no questions asked.

For TX loopback steering according to L2/L3/L4 headers, ConnectX-4 requires to copy the
corresponding headers into the send queue(SQ) WQE HW descriptor so it can decide whether to loop it back
or to forward to wire.

For legacy E-Switch mode only L2 headers copy is required.
For advanced steering (E-Switch offloads) more header layers may be required to be copied,
the required mode will be advertised by FW to each VF and PF according to the corresponding
E-Switch configuration.

Changes V2:
- Allocate query_nic_vport_context_out on the stack
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+105 -7
+8
drivers/net/ethernet/mellanox/mlx5/core/en.h
··· 129 129 } 130 130 } 131 131 132 + enum { 133 + MLX5E_INLINE_MODE_L2, 134 + MLX5E_INLINE_MODE_VPORT_CONTEXT, 135 + MLX5_INLINE_MODE_NOT_REQUIRED, 136 + }; 137 + 132 138 struct mlx5e_tx_wqe { 133 139 struct mlx5_wqe_ctrl_seg ctrl; 134 140 struct mlx5_wqe_eth_seg eth; ··· 194 188 bool lro_en; 195 189 u32 lro_wqe_sz; 196 190 u16 tx_max_inline; 191 + u8 tx_min_inline_mode; 197 192 u8 rss_hfunc; 198 193 u8 toeplitz_hash_key[40]; 199 194 u32 indirection_rqt[MLX5E_INDIR_RQT_SIZE]; ··· 405 398 u32 sqn; 406 399 u16 bf_buf_size; 407 400 u16 max_inline; 401 + u8 min_inline_mode; 408 402 u16 edge; 409 403 struct device *pdev; 410 404 struct mlx5e_tstamp *tstamp;
+24
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
··· 56 56 u32 sqc[MLX5_ST_SZ_DW(sqc)]; 57 57 struct mlx5_wq_param wq; 58 58 u16 max_inline; 59 + u8 min_inline_mode; 59 60 bool icosq; 60 61 }; 61 62 ··· 650 649 } 651 650 sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2; 652 651 sq->max_inline = param->max_inline; 652 + sq->min_inline_mode = 653 + MLX5_CAP_ETH(mdev, wqe_inline_mode) == MLX5E_INLINE_MODE_VPORT_CONTEXT ? 654 + param->min_inline_mode : 0; 653 655 654 656 err = mlx5e_alloc_sq_db(sq, cpu_to_node(c->cpu)); 655 657 if (err) ··· 735 731 736 732 MLX5_SET(sqc, sqc, tis_num_0, param->icosq ? 0 : priv->tisn[sq->tc]); 737 733 MLX5_SET(sqc, sqc, cqn, sq->cq.mcq.cqn); 734 + MLX5_SET(sqc, sqc, min_wqe_inline_mode, sq->min_inline_mode); 738 735 MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST); 739 736 MLX5_SET(sqc, sqc, tis_lst_sz, param->icosq ? 0 : 1); 740 737 MLX5_SET(sqc, sqc, flush_in_error_en, 1); ··· 1348 1343 MLX5_SET(wq, wq, log_wq_sz, priv->params.log_sq_size); 1349 1344 1350 1345 param->max_inline = priv->params.tx_max_inline; 1346 + param->min_inline_mode = priv->params.tx_min_inline_mode; 1351 1347 } 1352 1348 1353 1349 static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv, ··· 2984 2978 MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE; 2985 2979 } 2986 2980 2981 + static void mlx5e_query_min_inline(struct mlx5_core_dev *mdev, 2982 + u8 *min_inline_mode) 2983 + { 2984 + switch (MLX5_CAP_ETH(mdev, wqe_inline_mode)) { 2985 + case MLX5E_INLINE_MODE_L2: 2986 + *min_inline_mode = MLX5_INLINE_MODE_L2; 2987 + break; 2988 + case MLX5E_INLINE_MODE_VPORT_CONTEXT: 2989 + mlx5_query_nic_vport_min_inline(mdev, 2990 + min_inline_mode); 2991 + break; 2992 + case MLX5_INLINE_MODE_NOT_REQUIRED: 2993 + *min_inline_mode = MLX5_INLINE_MODE_NONE; 2994 + break; 2995 + } 2996 + } 2997 + 2987 2998 static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, 2988 2999 struct net_device *netdev, 2989 3000 const struct mlx5e_profile *profile, ··· 3066 3043 priv->params.tx_cq_moderation.pkts = 3067 3044 MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS; 3068 3045 priv->params.tx_max_inline = mlx5e_get_max_inline_cap(mdev); 3046 + mlx5e_query_min_inline(mdev, &priv->params.tx_min_inline_mode); 3069 3047 priv->params.num_tc = 1; 3070 3048 priv->params.rss_hfunc = ETH_RSS_HASH_XOR; 3071 3049
+45 -4
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
··· 128 128 return priv->channeltc_to_txq_map[channel_ix][up]; 129 129 } 130 130 131 + static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb) 132 + { 133 + #define MLX5E_MIN_INLINE (ETH_HLEN + VLAN_HLEN) 134 + 135 + return max(skb_network_offset(skb), MLX5E_MIN_INLINE); 136 + } 137 + 138 + static inline int mlx5e_skb_l3_header_offset(struct sk_buff *skb) 139 + { 140 + struct flow_keys keys; 141 + 142 + if (skb_transport_header_was_set(skb)) 143 + return skb_transport_offset(skb); 144 + else if (skb_flow_dissect_flow_keys(skb, &keys, 0)) 145 + return keys.control.thoff; 146 + else 147 + return mlx5e_skb_l2_header_offset(skb); 148 + } 149 + 150 + static inline unsigned int mlx5e_calc_min_inline(enum mlx5_inline_modes mode, 151 + struct sk_buff *skb) 152 + { 153 + int hlen; 154 + 155 + switch (mode) { 156 + case MLX5_INLINE_MODE_TCP_UDP: 157 + hlen = eth_get_headlen(skb->data, skb_headlen(skb)); 158 + if (hlen == ETH_HLEN && !skb_vlan_tag_present(skb)) 159 + hlen += VLAN_HLEN; 160 + return hlen; 161 + case MLX5_INLINE_MODE_IP: 162 + /* When transport header is set to zero, it means no transport 163 + * header. When transport header is set to 0xff's, it means 164 + * transport header wasn't set. 165 + */ 166 + if (skb_transport_offset(skb)) 167 + return mlx5e_skb_l3_header_offset(skb); 168 + /* fall through */ 169 + case MLX5_INLINE_MODE_L2: 170 + default: 171 + return mlx5e_skb_l2_header_offset(skb); 172 + } 173 + } 174 + 131 175 static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, 132 176 struct sk_buff *skb, bool bf) 133 177 { ··· 179 135 * headers and occur before the data gather. 180 136 * Therefore these headers must be copied into the WQE 181 137 */ 182 - #define MLX5E_MIN_INLINE (ETH_HLEN + VLAN_HLEN) 183 - 184 138 if (bf) { 185 139 u16 ihs = skb_headlen(skb); 186 140 ··· 188 146 if (ihs <= sq->max_inline) 189 147 return skb_headlen(skb); 190 148 } 191 - 192 - return max(skb_network_offset(skb), MLX5E_MIN_INLINE); 149 + return mlx5e_calc_min_inline(sq->min_inline_mode, skb); 193 150 } 194 151 195 152 static inline void mlx5e_tx_skb_pull_inline(unsigned char **skb_data,
+12
drivers/net/ethernet/mellanox/mlx5/core/vport.c
··· 135 135 return mlx5_cmd_exec_check_status(mdev, in, inlen, out, sizeof(out)); 136 136 } 137 137 138 + void mlx5_query_nic_vport_min_inline(struct mlx5_core_dev *mdev, 139 + u8 *min_inline_mode) 140 + { 141 + u32 out[MLX5_ST_SZ_DW(query_nic_vport_context_out)] = {0}; 142 + 143 + mlx5_query_nic_vport_context(mdev, 0, out, sizeof(out)); 144 + 145 + *min_inline_mode = MLX5_GET(query_nic_vport_context_out, out, 146 + nic_vport_context.min_wqe_inline_mode); 147 + } 148 + EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_min_inline); 149 + 138 150 int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, 139 151 u16 vport, u8 *addr) 140 152 {
+7
include/linux/mlx5/device.h
··· 129 129 tmp; \ 130 130 }) 131 131 132 + enum mlx5_inline_modes { 133 + MLX5_INLINE_MODE_NONE, 134 + MLX5_INLINE_MODE_L2, 135 + MLX5_INLINE_MODE_IP, 136 + MLX5_INLINE_MODE_TCP_UDP, 137 + }; 138 + 132 139 enum { 133 140 MLX5_MAX_COMMANDS = 32, 134 141 MLX5_CMD_DATA_BLOCK_SIZE = 512,
+7 -3
include/linux/mlx5/mlx5_ifc.h
··· 536 536 u8 self_lb_en_modifiable[0x1]; 537 537 u8 reserved_at_9[0x2]; 538 538 u8 max_lso_cap[0x5]; 539 - u8 reserved_at_10[0x4]; 539 + u8 reserved_at_10[0x2]; 540 + u8 wqe_inline_mode[0x2]; 540 541 u8 rss_ind_tbl_cap[0x4]; 541 542 u8 reg_umr_sq[0x1]; 542 543 u8 scatter_fcs[0x1]; ··· 2271 2270 u8 cd_master[0x1]; 2272 2271 u8 fre[0x1]; 2273 2272 u8 flush_in_error_en[0x1]; 2274 - u8 reserved_at_4[0x4]; 2273 + u8 reserved_at_4[0x1]; 2274 + u8 min_wqe_inline_mode[0x3]; 2275 2275 u8 state[0x4]; 2276 2276 u8 reg_umr[0x1]; 2277 2277 u8 reserved_at_d[0x13]; ··· 2369 2367 }; 2370 2368 2371 2369 struct mlx5_ifc_nic_vport_context_bits { 2372 - u8 reserved_at_0[0x1f]; 2370 + u8 reserved_at_0[0x5]; 2371 + u8 min_wqe_inline_mode[0x3]; 2372 + u8 reserved_at_8[0x17]; 2373 2373 u8 roce_en[0x1]; 2374 2374 2375 2375 u8 arm_change_event[0x1];
+2
include/linux/mlx5/vport.h
··· 43 43 u16 vport, u8 state); 44 44 int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, 45 45 u16 vport, u8 *addr); 46 + void mlx5_query_nic_vport_min_inline(struct mlx5_core_dev *mdev, 47 + u8 *min_inline); 46 48 int mlx5_modify_nic_vport_mac_address(struct mlx5_core_dev *dev, 47 49 u16 vport, u8 *addr); 48 50 int mlx5_query_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 *mtu);