Index: head/sys/dev/sfxge/common/ef10_rx.c =================================================================== --- head/sys/dev/sfxge/common/ef10_rx.c +++ head/sys/dev/sfxge/common/ef10_rx.c @@ -325,11 +325,32 @@ __in uint32_t rss_context, __in efx_rx_hash_type_t type) { + 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_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN, MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)]; efx_rc_t rc; + EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_TCP_LBN == + MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_LBN); + EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_TCP_WIDTH == + MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_WIDTH); + EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_LBN == + MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_LBN); + EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_WIDTH == + MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_WIDTH); + EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_TCP_LBN == + MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_LBN); + EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_TCP_WIDTH == + MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_WIDTH); + EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_LBN == + MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_LBN); + EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_WIDTH == + MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_WIDTH); + if (rss_context == EF10_RSS_CONTEXT_INVALID) { rc = EINVAL; goto fail1; @@ -345,15 +366,20 @@ 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_tcp = EFX_RX_HASH(IPV4_TCP, 4TUPLE); + type_ipv6 = EFX_RX_HASH(IPV6, 2TUPLE) | EFX_RX_HASH(IPV6_TCP, 2TUPLE); + type_ipv6_tcp = EFX_RX_HASH(IPV6_TCP, 4TUPLE); + MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS, RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN, - (type & EFX_RX_HASH_IPV4) ? 1 : 0, + ((type & type_ipv4) == type_ipv4) ? 1 : 0, RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN, - (type & EFX_RX_HASH_TCPIPV4) ? 1 : 0, + ((type & type_ipv4_tcp) == type_ipv4_tcp) ? 1 : 0, RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN, - (type & EFX_RX_HASH_IPV6) ? 1 : 0, + ((type & type_ipv6) == type_ipv6) ? 1 : 0, RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN, - (type & EFX_RX_HASH_TCPIPV6) ? 1 : 0); + ((type & type_ipv6_tcp) == type_ipv6_tcp) ? 1 : 0); efx_mcdi_execute(enp, &req); Index: head/sys/dev/sfxge/common/efx.h =================================================================== --- head/sys/dev/sfxge/common/efx.h +++ head/sys/dev/sfxge/common/efx.h @@ -2098,11 +2098,30 @@ EFX_RX_HASHALG_TOEPLITZ } efx_rx_hash_alg_t; +/* + * Legacy hash type flags. + * + * They represent standard tuples for distinct traffic classes. + */ #define EFX_RX_HASH_IPV4 (1U << 0) #define EFX_RX_HASH_TCPIPV4 (1U << 1) #define EFX_RX_HASH_IPV6 (1U << 2) #define EFX_RX_HASH_TCPIPV6 (1U << 3) +#define EFX_RX_HASH_LEGACY_MASK \ + (EFX_RX_HASH_IPV4 | \ + EFX_RX_HASH_TCPIPV4 | \ + EFX_RX_HASH_IPV6 | \ + EFX_RX_HASH_TCPIPV6) + +/* + * The type of the argument used by efx_rx_scale_mode_set() to + * provide a means for the client drivers to configure hashing. + * + * A properly constructed value can either be: + * - a combination of legacy flags + * - a combination of EFX_RX_HASH() flags + */ typedef unsigned int efx_rx_hash_type_t; typedef enum efx_rx_hash_support_e { @@ -2120,6 +2139,77 @@ EFX_RX_SCALE_EXCLUSIVE, /* Writable key/indirection table */ EFX_RX_SCALE_SHARED /* Read-only key/indirection table */ } efx_rx_scale_context_type_t; + +/* + * Traffic classes eligible for hash computation. + * + * Select packet headers used in computing the receive hash. + * This uses the same encoding as the RSS_MODES field of + * MC_CMD_RSS_CONTEXT_SET_FLAGS. + */ +#define EFX_RX_CLASS_IPV4_TCP_LBN 8 +#define EFX_RX_CLASS_IPV4_TCP_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_LBN 28 +#define EFX_RX_CLASS_IPV6_WIDTH 4 + +#define EFX_RX_NCLASSES 4 + +/* + * Ancillary flags used to construct generic hash tuples. + * This uses the same encoding as RSS_MODE_HASH_SELECTOR. + */ +#define EFX_RX_CLASS_HASH_SRC_ADDR (1U << 0) +#define EFX_RX_CLASS_HASH_DST_ADDR (1U << 1) +#define EFX_RX_CLASS_HASH_SRC_PORT (1U << 2) +#define EFX_RX_CLASS_HASH_DST_PORT (1U << 3) + +/* + * Generic hash tuples. + * + * They express combinations of packet fields + * which can contribute to the hash value for + * a particular traffic class. + */ +#define EFX_RX_CLASS_HASH_DISABLE 0 + +#define EFX_RX_CLASS_HASH_2TUPLE \ + (EFX_RX_CLASS_HASH_SRC_ADDR | \ + EFX_RX_CLASS_HASH_DST_ADDR) + +#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 + +/* + * Hash flag constructor. + * + * Resulting flags encode hash tuples for specific traffic classes. + * The client drivers are encouraged to use these flags to form + * a hash type value. + */ +#define EFX_RX_HASH(_class, _tuple) \ + EFX_INSERT_FIELD_NATIVE32(0, 31, \ + EFX_RX_CLASS_##_class, EFX_RX_CLASS_HASH_##_tuple) + +/* + * The maximum number of EFX_RX_HASH() flags. + */ +#define EFX_RX_HASH_NFLAGS (EFX_RX_NCLASSES * EFX_RX_CLASS_HASH_NTUPLES) + +extern __checkReturn efx_rc_t +efx_rx_scale_hash_flags_get( + __in efx_nic_t *enp, + __in efx_rx_hash_alg_t hash_alg, + __inout_ecount(EFX_RX_HASH_NFLAGS) unsigned int *flagsp, + __out unsigned int *nflagsp); extern __checkReturn efx_rc_t efx_rx_hash_default_support_get( Index: head/sys/dev/sfxge/common/efx_rx.c =================================================================== --- head/sys/dev/sfxge/common/efx_rx.c +++ head/sys/dev/sfxge/common/efx_rx.c @@ -323,6 +323,61 @@ #endif /* EFSYS_OPT_RX_SCATTER */ #if EFSYS_OPT_RX_SCALE + __checkReturn efx_rc_t +efx_rx_scale_hash_flags_get( + __in efx_nic_t *enp, + __in efx_rx_hash_alg_t hash_alg, + __inout_ecount(EFX_RX_HASH_NFLAGS) unsigned int *flagsp, + __out unsigned int *nflagsp) +{ + unsigned int *entryp = flagsp; + efx_rc_t rc; + + if (flagsp == NULL || nflagsp == NULL) { + rc = EINVAL; + goto fail1; + } + +#define LIST_FLAGS(_entryp, _class, _l4_hashing) \ + do { \ + if (_l4_hashing) \ + *(_entryp++) = EFX_RX_HASH(_class, 4TUPLE); \ + \ + *(_entryp++) = EFX_RX_HASH(_class, 2TUPLE); \ + *(_entryp++) = EFX_RX_HASH(_class, DISABLE); \ + \ + _NOTE(CONSTANTCONDITION) \ + } while (B_FALSE) + + 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); + break; + + default: + rc = EINVAL; + goto fail2; + } + +#undef LIST_FLAGS + + *nflagsp = (unsigned int)(entryp - flagsp); + EFSYS_ASSERT3U(*nflagsp, <=, EFX_RX_HASH_NFLAGS); + + return (0); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + __checkReturn efx_rc_t efx_rx_hash_default_support_get( __in efx_nic_t *enp, @@ -454,19 +509,80 @@ __in boolean_t insert) { const efx_rx_ops_t *erxop = enp->en_erxop; + unsigned int type_flags[EFX_RX_HASH_NFLAGS]; + unsigned int type_nflags; + efx_rx_hash_type_t type_check; + unsigned int i; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); + /* + * Legacy flags and modern bits cannot be + * used at the same time in the hash type. + */ + if ((type & EFX_RX_HASH_LEGACY_MASK) && + (type & ~EFX_RX_HASH_LEGACY_MASK)) { + rc = EINVAL; + goto fail1; + } + + /* + * Translate legacy flags to the new representation + * so that chip-specific handlers will consider the + * new flags only. + */ + if (type & EFX_RX_HASH_IPV4) { + type |= EFX_RX_HASH(IPV4, 2TUPLE); + type |= EFX_RX_HASH(IPV4_TCP, 2TUPLE); + } + + if (type & EFX_RX_HASH_TCPIPV4) + type |= EFX_RX_HASH(IPV4_TCP, 4TUPLE); + + if (type & EFX_RX_HASH_IPV6) { + type |= EFX_RX_HASH(IPV6, 2TUPLE); + type |= EFX_RX_HASH(IPV6_TCP, 2TUPLE); + } + + if (type & EFX_RX_HASH_TCPIPV6) + type |= EFX_RX_HASH(IPV6_TCP, 4TUPLE); + + type &= ~EFX_RX_HASH_LEGACY_MASK; + type_check = type; + + /* + * Get the list of supported hash flags and sanitise the input. + */ + rc = efx_rx_scale_hash_flags_get(enp, alg, type_flags, &type_nflags); + if (rc != 0) + goto fail2; + + for (i = 0; i < type_nflags; ++i) { + if ((type_check & type_flags[i]) == type_flags[i]) + type_check &= ~(type_flags[i]); + } + + if (type_check != 0) { + rc = EINVAL; + goto fail3; + } + if (erxop->erxo_scale_mode_set != NULL) { if ((rc = erxop->erxo_scale_mode_set(enp, rss_context, alg, type, insert)) != 0) - goto fail1; + goto fail4; } return (0); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); @@ -806,7 +922,7 @@ efx_rc_t rc; nbuf32 = buf_size / 32; - if ((nbuf32 == 0) || + IF ((NBUF32 == 0) || (nbuf32 >= (1 << FRF_BZ_RX_USR_BUF_SIZE_WIDTH)) || ((buf_size % 32) != 0)) { rc = EINVAL; @@ -910,6 +1026,10 @@ __in efx_rx_hash_type_t type, __in boolean_t insert) { + efx_rx_hash_type_t type_ipv4 = EFX_RX_HASH(IPV4, 2TUPLE); + efx_rx_hash_type_t type_ipv4_tcp = EFX_RX_HASH(IPV4_TCP, 4TUPLE); + efx_rx_hash_type_t type_ipv6 = EFX_RX_HASH(IPV6, 2TUPLE); + efx_rx_hash_type_t type_ipv6_tcp = EFX_RX_HASH(IPV6_TCP, 4TUPLE); efx_rc_t rc; if (rss_context != EFX_RSS_CONTEXT_DEFAULT) { @@ -924,12 +1044,12 @@ case EFX_RX_HASHALG_TOEPLITZ: EFX_RX_TOEPLITZ_IPV4_HASH(enp, insert, - type & EFX_RX_HASH_IPV4, - type & EFX_RX_HASH_TCPIPV4); + (type & type_ipv4) == type_ipv4, + (type & type_ipv4_tcp) == type_ipv4_tcp); EFX_RX_TOEPLITZ_IPV6_HASH(enp, - type & EFX_RX_HASH_IPV6, - type & EFX_RX_HASH_TCPIPV6, + (type & type_ipv6) == type_ipv6, + (type & type_ipv6_tcp) == type_ipv6_tcp, rc); if (rc != 0) goto fail2;