+ __checkReturn efx_rc_t
+efx_rx_scale_hash_flags_get(
+ __in efx_nic_t *enp,
+ __in efx_rx_hash_alg_t hash_alg,
+ __out_ecount_part(max_nflags, *nflagsp) unsigned int *flagsp,
+ __in unsigned int max_nflags,
+ __out unsigned int *nflagsp)
+{
+ efx_nic_cfg_t *encp = &enp->en_nic_cfg;
+ unsigned int nflags = 0;
+ efx_rc_t rc;
+
+ if (flagsp == NULL || nflagsp == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ if ((encp->enc_rx_scale_hash_alg_mask & (1U << hash_alg)) == 0) {
+ nflags = 0;
+ goto done;
+ }
+
+ /* Helper to add flags word to flags array without buffer overflow */
+#define INSERT_FLAGS(_flags) \
+ do { \
+ if (nflags >= max_nflags) { \
+ rc = E2BIG; \
+ goto fail2; \
+ } \
+ *(flagsp + nflags) = (_flags); \
+ nflags++; \
+ \
+ _NOTE(CONSTANTCONDITION) \
+ } while (B_FALSE)
+
+ if (encp->enc_rx_scale_l4_hash_supported != B_FALSE) {
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 4TUPLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 4TUPLE));
+ }
+
+ if ((encp->enc_rx_scale_l4_hash_supported != B_FALSE) &&
+ (encp->enc_rx_scale_additional_modes_supported != B_FALSE)) {
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 2TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 2TUPLE_SRC));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 2TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 2TUPLE_SRC));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 4TUPLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 2TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 2TUPLE_SRC));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 4TUPLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 2TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 2TUPLE_SRC));
+ }
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 2TUPLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 2TUPLE));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV4, 2TUPLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6, 2TUPLE));
+
+ if (encp->enc_rx_scale_additional_modes_supported != B_FALSE) {
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 1TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 1TUPLE_SRC));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 1TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 1TUPLE_SRC));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 2TUPLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 1TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 1TUPLE_SRC));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 2TUPLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 1TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 1TUPLE_SRC));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV4, 1TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV4, 1TUPLE_SRC));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV6, 1TUPLE_DST));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6, 1TUPLE_SRC));
+ }
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, DISABLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, DISABLE));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, DISABLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, DISABLE));
+
+ INSERT_FLAGS(EFX_RX_HASH(IPV4, DISABLE));
+ INSERT_FLAGS(EFX_RX_HASH(IPV6, DISABLE));
+
+#undef INSERT_FLAGS
+
+done:
+ *nflagsp = nflags;
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+