__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;
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);
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 {
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 *flags,
+ __out unsigned int *nflagsp);
+
extern __checkReturn efx_rc_t
efx_rx_hash_default_support_get(
__in efx_nic_t *enp,
#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 *flags,
+ __out unsigned int *nflagsp)
+{
+ unsigned int *entryp = flags;
+ efx_rc_t rc;
+
+ if (flags == 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 - flags);
+ 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,
__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);
__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) {
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;