net/sfc/base: support more RSS hash configurations
authorIvan Malov <ivan.malov@oktetlabs.ru>
Wed, 25 Apr 2018 17:51:39 +0000 (18:51 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 27 Apr 2018 17:00:55 +0000 (18:00 +0100)
Modern firmwares on EF10 adapters have support for
more traffic classes eligible for hash computation.
Also, it has become possible to adjust hashing per
individual class and select distinct packet fields
which will be able to contribute to the hash value.

This patch adds support for the mentioned features.

Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
drivers/net/sfc/base/ef10_nic.c
drivers/net/sfc/base/ef10_rx.c
drivers/net/sfc/base/efx.h
drivers/net/sfc/base/efx_rx.c
drivers/net/sfc/base/siena_nic.c

index ca11ff4..fa4f7a2 100644 (file)
@@ -1041,6 +1041,12 @@ ef10_get_datapath_caps(
        }
        encp->enc_rx_prefix_size = 14;
 
+       /* Check if the firmware supports additional RSS modes */
+       if (CAP_FLAGS1(req, ADDITIONAL_RSS_MODES))
+               encp->enc_rx_scale_additional_modes_supported = B_TRUE;
+       else
+               encp->enc_rx_scale_additional_modes_supported = B_FALSE;
+
        /* Check if the firmware supports TSO */
        if (CAP_FLAGS1(req, TX_TSO))
                encp->enc_fw_assisted_tso_enabled = B_TRUE;
index d1971e3..28b8004 100644 (file)
@@ -298,10 +298,12 @@ efx_mcdi_rss_context_set_flags(
        __in            uint32_t rss_context,
        __in            efx_rx_hash_type_t type)
 {
+       efx_nic_cfg_t *encp = &enp->en_nic_cfg;
        efx_rx_hash_type_t type_ipv4;
        efx_rx_hash_type_t type_ipv4_tcp;
        efx_rx_hash_type_t type_ipv6;
        efx_rx_hash_type_t type_ipv6_tcp;
+       efx_rx_hash_type_t modes;
        efx_mcdi_req_t req;
        uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
                            MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)];
@@ -339,12 +341,35 @@ efx_mcdi_rss_context_set_flags(
        MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
            rss_context);
 
-       type_ipv4 = EFX_RX_HASH(IPV4, 2TUPLE) | EFX_RX_HASH(IPV4_TCP, 2TUPLE);
+       type_ipv4 = EFX_RX_HASH(IPV4, 2TUPLE) | EFX_RX_HASH(IPV4_TCP, 2TUPLE) |
+                   EFX_RX_HASH(IPV4_UDP, 2TUPLE);
        type_ipv4_tcp = EFX_RX_HASH(IPV4_TCP, 4TUPLE);
-       type_ipv6 = EFX_RX_HASH(IPV6, 2TUPLE) | EFX_RX_HASH(IPV6_TCP, 2TUPLE);
+       type_ipv6 = EFX_RX_HASH(IPV6, 2TUPLE) | EFX_RX_HASH(IPV6_TCP, 2TUPLE) |
+                   EFX_RX_HASH(IPV6_UDP, 2TUPLE);
        type_ipv6_tcp = EFX_RX_HASH(IPV6_TCP, 4TUPLE);
 
-       MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
+       /*
+        * Create a copy of the original hash type.
+        * The copy will be used to fill in RSS_MODE bits and
+        * may be cleared beforehand. The original variable
+        * and, thus, EN bits will remain unaffected.
+        */
+       modes = type;
+
+       /*
+        * If the firmware lacks support for additional modes, RSS_MODE
+        * fields must contain zeros, otherwise the operation will fail.
+        */
+       if (encp->enc_rx_scale_additional_modes_supported == B_FALSE)
+               modes = 0;
+
+#define        EXTRACT_RSS_MODE(_type, _class)         \
+       (EFX_EXTRACT_NATIVE(_type, 0, 31,       \
+       EFX_LOW_BIT(EFX_RX_CLASS_##_class),     \
+       EFX_HIGH_BIT(EFX_RX_CLASS_##_class)) &  \
+       EFX_MASK32(EFX_RX_CLASS_##_class))
+
+       MCDI_IN_POPULATE_DWORD_10(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
            RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
            ((type & type_ipv4) == type_ipv4) ? 1 : 0,
            RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
@@ -352,7 +377,21 @@ efx_mcdi_rss_context_set_flags(
            RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
            ((type & type_ipv6) == type_ipv6) ? 1 : 0,
            RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
-           ((type & type_ipv6_tcp) == type_ipv6_tcp) ? 1 : 0);
+           ((type & type_ipv6_tcp) == type_ipv6_tcp) ? 1 : 0,
+           RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE,
+           EXTRACT_RSS_MODE(modes, IPV4_TCP),
+           RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV4_RSS_MODE,
+           EXTRACT_RSS_MODE(modes, IPV4_UDP),
+           RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE,
+           EXTRACT_RSS_MODE(modes, IPV4),
+           RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE,
+           EXTRACT_RSS_MODE(modes, IPV6_TCP),
+           RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV6_RSS_MODE,
+           EXTRACT_RSS_MODE(modes, IPV6_UDP),
+           RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE,
+           EXTRACT_RSS_MODE(modes, IPV6));
+
+#undef EXTRACT_RSS_MODE
 
        efx_mcdi_execute(enp, &req);
 
index 41aa505..21d2545 100644 (file)
@@ -1192,6 +1192,7 @@ typedef struct efx_nic_cfg_s {
        uint32_t                enc_rx_buf_align_start;
        uint32_t                enc_rx_buf_align_end;
        uint32_t                enc_rx_scale_max_exclusive_contexts;
+       boolean_t               enc_rx_scale_additional_modes_supported;
 #if EFSYS_OPT_LOOPBACK
        efx_qword_t             enc_loopback_types[EFX_LINK_NMODES];
 #endif /* EFSYS_OPT_LOOPBACK */
@@ -2120,14 +2121,18 @@ typedef enum efx_rx_scale_context_type_e {
  */
 #define        EFX_RX_CLASS_IPV4_TCP_LBN       8
 #define        EFX_RX_CLASS_IPV4_TCP_WIDTH     4
+#define        EFX_RX_CLASS_IPV4_UDP_LBN       12
+#define        EFX_RX_CLASS_IPV4_UDP_WIDTH     4
 #define        EFX_RX_CLASS_IPV4_LBN           16
 #define        EFX_RX_CLASS_IPV4_WIDTH         4
 #define        EFX_RX_CLASS_IPV6_TCP_LBN       20
 #define        EFX_RX_CLASS_IPV6_TCP_WIDTH     4
+#define        EFX_RX_CLASS_IPV6_UDP_LBN       24
+#define        EFX_RX_CLASS_IPV6_UDP_WIDTH     4
 #define        EFX_RX_CLASS_IPV6_LBN           28
 #define        EFX_RX_CLASS_IPV6_WIDTH         4
 
-#define        EFX_RX_NCLASSES                 4
+#define        EFX_RX_NCLASSES                 6
 
 /*
  * Ancillary flags used to construct generic hash tuples.
@@ -2147,17 +2152,28 @@ typedef enum efx_rx_scale_context_type_e {
  */
 #define        EFX_RX_CLASS_HASH_DISABLE       0
 
+#define        EFX_RX_CLASS_HASH_1TUPLE_SRC    EFX_RX_CLASS_HASH_SRC_ADDR
+#define        EFX_RX_CLASS_HASH_1TUPLE_DST    EFX_RX_CLASS_HASH_DST_ADDR
+
 #define        EFX_RX_CLASS_HASH_2TUPLE                \
        (EFX_RX_CLASS_HASH_SRC_ADDR     |       \
        EFX_RX_CLASS_HASH_DST_ADDR)
 
+#define        EFX_RX_CLASS_HASH_2TUPLE_SRC            \
+       (EFX_RX_CLASS_HASH_SRC_ADDR     |       \
+       EFX_RX_CLASS_HASH_SRC_PORT)
+
+#define        EFX_RX_CLASS_HASH_2TUPLE_DST            \
+       (EFX_RX_CLASS_HASH_DST_ADDR     |       \
+       EFX_RX_CLASS_HASH_DST_PORT)
+
 #define        EFX_RX_CLASS_HASH_4TUPLE                \
        (EFX_RX_CLASS_HASH_SRC_ADDR     |       \
        EFX_RX_CLASS_HASH_DST_ADDR      |       \
        EFX_RX_CLASS_HASH_SRC_PORT      |       \
        EFX_RX_CLASS_HASH_DST_PORT)
 
-#define EFX_RX_CLASS_HASH_NTUPLES      3
+#define EFX_RX_CLASS_HASH_NTUPLES      7
 
 /*
  * Hash flag constructor.
index a9995b4..b02c7f6 100644 (file)
@@ -301,6 +301,8 @@ efx_rx_scale_hash_flags_get(
        __inout_ecount(EFX_RX_HASH_NFLAGS)      unsigned int *flags,
        __out                                   unsigned int *nflagsp)
 {
+       efx_nic_cfg_t *encp = &enp->en_nic_cfg;
+       boolean_t additional_modes;
        unsigned int *entryp = flags;
        efx_rc_t rc;
 
@@ -309,12 +311,28 @@ efx_rx_scale_hash_flags_get(
                goto fail1;
        }
 
-#define        LIST_FLAGS(_entryp, _class, _l4_hashing)                        \
+       additional_modes = encp->enc_rx_scale_additional_modes_supported;
+
+#define        LIST_FLAGS(_entryp, _class, _l4_hashing, _additional_modes)     \
        do {                                                            \
-               if (_l4_hashing)                                        \
+               if (_l4_hashing) {                                      \
                        *(_entryp++) = EFX_RX_HASH(_class, 4TUPLE);     \
                                                                        \
+                       if (_additional_modes) {                        \
+                               *(_entryp++) =                          \
+                                   EFX_RX_HASH(_class, 2TUPLE_DST);    \
+                               *(_entryp++) =                          \
+                                   EFX_RX_HASH(_class, 2TUPLE_SRC);    \
+                       }                                               \
+               }                                                       \
+                                                                       \
                *(_entryp++) = EFX_RX_HASH(_class, 2TUPLE);             \
+                                                                       \
+               if (_additional_modes) {                                \
+                       *(_entryp++) = EFX_RX_HASH(_class, 1TUPLE_DST); \
+                       *(_entryp++) = EFX_RX_HASH(_class, 1TUPLE_SRC); \
+               }                                                       \
+                                                                       \
                *(_entryp++) = EFX_RX_HASH(_class, DISABLE);            \
                                                                        \
                _NOTE(CONSTANTCONDITION)                                \
@@ -322,10 +340,16 @@ efx_rx_scale_hash_flags_get(
 
        switch (hash_alg) {
        case EFX_RX_HASHALG_TOEPLITZ:
-               LIST_FLAGS(entryp, IPV4_TCP, B_TRUE);
-               LIST_FLAGS(entryp, IPV6_TCP, B_TRUE);
-               LIST_FLAGS(entryp, IPV4, B_FALSE);
-               LIST_FLAGS(entryp, IPV6, B_FALSE);
+               LIST_FLAGS(entryp, IPV4_TCP, B_TRUE, additional_modes);
+               LIST_FLAGS(entryp, IPV6_TCP, B_TRUE, additional_modes);
+
+               if (additional_modes) {
+                       LIST_FLAGS(entryp, IPV4_UDP, B_TRUE, additional_modes);
+                       LIST_FLAGS(entryp, IPV6_UDP, B_TRUE, additional_modes);
+               }
+
+               LIST_FLAGS(entryp, IPV4, B_FALSE, additional_modes);
+               LIST_FLAGS(entryp, IPV6, B_FALSE, additional_modes);
                break;
 
        default:
@@ -507,6 +531,7 @@ efx_rx_scale_mode_set(
        if (type & EFX_RX_HASH_IPV4) {
                type |= EFX_RX_HASH(IPV4, 2TUPLE);
                type |= EFX_RX_HASH(IPV4_TCP, 2TUPLE);
+               type |= EFX_RX_HASH(IPV4_UDP, 2TUPLE);
        }
 
        if (type & EFX_RX_HASH_TCPIPV4)
@@ -515,6 +540,7 @@ efx_rx_scale_mode_set(
        if (type & EFX_RX_HASH_IPV6) {
                type |= EFX_RX_HASH(IPV6, 2TUPLE);
                type |= EFX_RX_HASH(IPV6_TCP, 2TUPLE);
+               type |= EFX_RX_HASH(IPV6_UDP, 2TUPLE);
        }
 
        if (type & EFX_RX_HASH_TCPIPV6)
index 6e57de4..0d6d071 100644 (file)
@@ -118,6 +118,9 @@ siena_board_cfg(
        /* There is one RSS context per function */
        encp->enc_rx_scale_max_exclusive_contexts = 1;
 
+       /* There is no support for additional RSS modes */
+       encp->enc_rx_scale_additional_modes_supported = B_FALSE;
+
        encp->enc_tx_dma_desc_size_max = EFX_MASK32(FSF_AZ_TX_KER_BYTE_COUNT);
        /* Fragments must not span 4k boundaries. */
        encp->enc_tx_dma_desc_boundary = 4096;