From: Aya Levin <a...@mellanox.com>

Enable user configuration of RX hash fields that are used for traffic
spreading into RX queues. User can change built-in RSS (Receive Side
Scaling) profiles on the following traffic types: UDP4, UDP6, TCP4 and
TCP6.  This configuration effects both outer and inner headers.  Added
support for ethtool commands: ETHTOOL_SRXFH and ETHTOOL_GRXFH.

Command example respectively:
$ethtool -N eth1 rx-flow-hash tcp4 sdfn
$ethtool -n eth1 rx-flow-hash tcpp4
IP SA
IP DA
L4 bytes 0 & 1 [TCP/UDP src port]
L4 bytes 2 & 3 [TCP/UDP dst port]

Signed-off-by: Aya Levin <a...@mellanox.com>
Reviewed-by: Tariq Toukan <tar...@mellanox.com>
Signed-off-by: Saeed Mahameed <sae...@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en.h  |   1 +
 .../mellanox/mlx5/core/en_fs_ethtool.c        | 112 ++++++++++++++++++
 .../net/ethernet/mellanox/mlx5/core/en_main.c |  27 ++++-
 3 files changed, 134 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h 
b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 330c476c1df2..c6686256a92a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -650,6 +650,7 @@ enum {
 
 struct mlx5e_rss_params {
        u32     indirection_rqt[MLX5E_INDIR_RQT_SIZE];
+       u32     rx_hash_fields[MLX5E_NUM_INDIR_TIRS];
        u8      toeplitz_hash_key[40];
        u8      hfunc;
 };
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
index c18dcebe1462..4421c10f58ae 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
@@ -771,6 +771,112 @@ void mlx5e_ethtool_init_steering(struct mlx5e_priv *priv)
        INIT_LIST_HEAD(&priv->fs.ethtool.rules);
 }
 
+static enum mlx5e_traffic_types flow_type_to_traffic_type(u32 flow_type)
+{
+       switch (flow_type) {
+       case TCP_V4_FLOW:
+               return  MLX5E_TT_IPV4_TCP;
+       case TCP_V6_FLOW:
+               return MLX5E_TT_IPV6_TCP;
+       case UDP_V4_FLOW:
+               return MLX5E_TT_IPV4_UDP;
+       case UDP_V6_FLOW:
+               return MLX5E_TT_IPV6_UDP;
+       case AH_V4_FLOW:
+               return MLX5E_TT_IPV4_IPSEC_AH;
+       case AH_V6_FLOW:
+               return MLX5E_TT_IPV6_IPSEC_AH;
+       case ESP_V4_FLOW:
+               return MLX5E_TT_IPV4_IPSEC_ESP;
+       case ESP_V6_FLOW:
+               return MLX5E_TT_IPV6_IPSEC_ESP;
+       case IPV4_FLOW:
+               return MLX5E_TT_IPV4;
+       case IPV6_FLOW:
+               return MLX5E_TT_IPV6;
+       default:
+               return MLX5E_NUM_INDIR_TIRS;
+       }
+}
+
+static int mlx5e_set_rss_hash_opt(struct mlx5e_priv *priv,
+                                 struct ethtool_rxnfc *nfc)
+{
+       int inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+       enum mlx5e_traffic_types tt;
+       u8 rx_hash_field = 0;
+       void *in;
+
+       tt = flow_type_to_traffic_type(nfc->flow_type);
+       if (tt == MLX5E_NUM_INDIR_TIRS)
+               return -EINVAL;
+
+       /*  RSS does not support anything other than hashing to queues
+        *  on src IP, dest IP, TCP/UDP src port and TCP/UDP dest
+        *  port.
+        */
+       if (nfc->flow_type != TCP_V4_FLOW &&
+           nfc->flow_type != TCP_V6_FLOW &&
+           nfc->flow_type != UDP_V4_FLOW &&
+           nfc->flow_type != UDP_V6_FLOW)
+               return -EOPNOTSUPP;
+
+       if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
+                         RXH_L4_B_0_1 | RXH_L4_B_2_3))
+               return -EOPNOTSUPP;
+
+       if (nfc->data & RXH_IP_SRC)
+               rx_hash_field |= MLX5_HASH_FIELD_SEL_SRC_IP;
+       if (nfc->data & RXH_IP_DST)
+               rx_hash_field |= MLX5_HASH_FIELD_SEL_DST_IP;
+       if (nfc->data & RXH_L4_B_0_1)
+               rx_hash_field |= MLX5_HASH_FIELD_SEL_L4_SPORT;
+       if (nfc->data & RXH_L4_B_2_3)
+               rx_hash_field |= MLX5_HASH_FIELD_SEL_L4_DPORT;
+
+       in = kvzalloc(inlen, GFP_KERNEL);
+       if (!in)
+               return -ENOMEM;
+
+       mutex_lock(&priv->state_lock);
+
+       if (rx_hash_field == priv->rss_params.rx_hash_fields[tt])
+               goto out;
+
+       priv->rss_params.rx_hash_fields[tt] = rx_hash_field;
+       mlx5e_modify_tirs_hash(priv, in, inlen);
+
+out:
+       mutex_unlock(&priv->state_lock);
+       kvfree(in);
+       return 0;
+}
+
+static int mlx5e_get_rss_hash_opt(struct mlx5e_priv *priv,
+                                 struct ethtool_rxnfc *nfc)
+{
+       enum mlx5e_traffic_types tt;
+       u32 hash_field = 0;
+
+       tt = flow_type_to_traffic_type(nfc->flow_type);
+       if (tt == MLX5E_NUM_INDIR_TIRS)
+               return -EINVAL;
+
+       hash_field = priv->rss_params.rx_hash_fields[tt];
+       nfc->data = 0;
+
+       if (hash_field & MLX5_HASH_FIELD_SEL_SRC_IP)
+               nfc->data |= RXH_IP_SRC;
+       if (hash_field & MLX5_HASH_FIELD_SEL_DST_IP)
+               nfc->data |= RXH_IP_DST;
+       if (hash_field & MLX5_HASH_FIELD_SEL_L4_SPORT)
+               nfc->data |= RXH_L4_B_0_1;
+       if (hash_field & MLX5_HASH_FIELD_SEL_L4_DPORT)
+               nfc->data |= RXH_L4_B_2_3;
+
+       return 0;
+}
+
 int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
 {
        int err = 0;
@@ -783,6 +889,9 @@ int mlx5e_set_rxnfc(struct net_device *dev, struct 
ethtool_rxnfc *cmd)
        case ETHTOOL_SRXCLSRLDEL:
                err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location);
                break;
+       case ETHTOOL_SRXFH:
+               err = mlx5e_set_rss_hash_opt(priv, cmd);
+               break;
        default:
                err = -EOPNOTSUPP;
                break;
@@ -810,6 +919,9 @@ int mlx5e_get_rxnfc(struct net_device *dev,
        case ETHTOOL_GRXCLSRLALL:
                err = mlx5e_ethtool_get_all_flows(priv, info, rule_locs);
                break;
+       case ETHTOOL_GRXFH:
+               err =  mlx5e_get_rss_hash_opt(priv, info);
+               break;
        default:
                err = -EOPNOTSUPP;
                break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index be782c508f3a..544c287c6481 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2695,20 +2695,30 @@ void mlx5e_build_indir_tir_ctx_hash(struct 
mlx5e_rss_params *rss_params,
                 ttconfig->rx_hash_fields);
 }
 
+static void mlx5e_update_rx_hash_fields(struct mlx5e_tirc_config *ttconfig,
+                                       enum mlx5e_traffic_types tt,
+                                       u32 rx_hash_fields)
+{
+       *ttconfig                = tirc_default_config[tt];
+       ttconfig->rx_hash_fields = rx_hash_fields;
+}
+
 void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen)
 {
        void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx);
+       struct mlx5e_rss_params *rss = &priv->rss_params;
        struct mlx5_core_dev *mdev = priv->mdev;
        int ctxlen = MLX5_ST_SZ_BYTES(tirc);
+       struct mlx5e_tirc_config ttconfig;
        int tt;
 
        MLX5_SET(modify_tir_in, in, bitmask.hash, 1);
 
        for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
                memset(tirc, 0, ctxlen);
-               mlx5e_build_indir_tir_ctx_hash(&priv->rss_params,
-                                              &tirc_default_config[tt],
-                                              tirc, false);
+               mlx5e_update_rx_hash_fields(&ttconfig, tt,
+                                           rss->rx_hash_fields[tt]);
+               mlx5e_build_indir_tir_ctx_hash(rss, &ttconfig, tirc, false);
                mlx5_core_modify_tir(mdev, priv->indir_tir[tt].tirn, in, inlen);
        }
 
@@ -2717,9 +2727,9 @@ void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void 
*in, int inlen)
 
        for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
                memset(tirc, 0, ctxlen);
-               mlx5e_build_indir_tir_ctx_hash(&priv->rss_params,
-                                              &tirc_default_config[tt],
-                                              tirc, true);
+               mlx5e_update_rx_hash_fields(&ttconfig, tt,
+                                           rss->rx_hash_fields[tt]);
+               mlx5e_build_indir_tir_ctx_hash(rss, &ttconfig, tirc, true);
                mlx5_core_modify_tir(mdev, priv->inner_indir_tir[tt].tirn, in,
                                     inlen);
        }
@@ -4514,11 +4524,16 @@ void mlx5e_build_rq_params(struct mlx5_core_dev *mdev,
 void mlx5e_build_rss_params(struct mlx5e_rss_params *rss_params,
                            u16 num_channels)
 {
+       enum mlx5e_traffic_types tt;
+
        rss_params->hfunc = ETH_RSS_HASH_XOR;
        netdev_rss_key_fill(rss_params->toeplitz_hash_key,
                            sizeof(rss_params->toeplitz_hash_key));
        mlx5e_build_default_indir_rqt(rss_params->indirection_rqt,
                                      MLX5E_INDIR_RQT_SIZE, num_channels);
+       for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
+               rss_params->rx_hash_fields[tt] =
+                       tirc_default_config[tt].rx_hash_fields;
 }
 
 void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
-- 
2.19.2

Reply via email to