|
@@ -2245,6 +2245,86 @@ static void efx_ef10_tx_write(struct efx_tx_queue *tx_queue)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#define RSS_MODE_HASH_ADDRS (1 << RSS_MODE_HASH_SRC_ADDR_LBN |\
|
|
|
|
+ 1 << RSS_MODE_HASH_DST_ADDR_LBN)
|
|
|
|
+#define RSS_MODE_HASH_PORTS (1 << RSS_MODE_HASH_SRC_PORT_LBN |\
|
|
|
|
+ 1 << RSS_MODE_HASH_DST_PORT_LBN)
|
|
|
|
+#define RSS_CONTEXT_FLAGS_DEFAULT (1 << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_IPV4_EN_LBN |\
|
|
|
|
+ 1 << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_TCPV4_EN_LBN |\
|
|
|
|
+ 1 << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_IPV6_EN_LBN |\
|
|
|
|
+ 1 << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_TCPV6_EN_LBN |\
|
|
|
|
+ (RSS_MODE_HASH_ADDRS | RSS_MODE_HASH_PORTS) << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV4_RSS_MODE_LBN |\
|
|
|
|
+ RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV4_RSS_MODE_LBN |\
|
|
|
|
+ RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV4_RSS_MODE_LBN |\
|
|
|
|
+ (RSS_MODE_HASH_ADDRS | RSS_MODE_HASH_PORTS) << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV6_RSS_MODE_LBN |\
|
|
|
|
+ RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN |\
|
|
|
|
+ RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_LBN)
|
|
|
|
+
|
|
|
|
+static int efx_ef10_get_rss_flags(struct efx_nic *efx, u32 context, u32 *flags)
|
|
|
|
+{
|
|
|
|
+ /* Firmware had a bug (sfc bug 61952) where it would not actually
|
|
|
|
+ * fill in the flags field in the response to MC_CMD_RSS_CONTEXT_GET_FLAGS.
|
|
|
|
+ * This meant that it would always contain whatever was previously
|
|
|
|
+ * in the MCDI buffer. Fortunately, all firmware versions with
|
|
|
|
+ * this bug have the same default flags value for a newly-allocated
|
|
|
|
+ * RSS context, and the only time we want to get the flags is just
|
|
|
|
+ * after allocating. Moreover, the response has a 32-bit hole
|
|
|
|
+ * where the context ID would be in the request, so we can use an
|
|
|
|
+ * overlength buffer in the request and pre-fill the flags field
|
|
|
|
+ * with what we believe the default to be. Thus if the firmware
|
|
|
|
+ * has the bug, it will leave our pre-filled value in the flags
|
|
|
|
+ * field of the response, and we will get the right answer.
|
|
|
|
+ *
|
|
|
|
+ * However, this does mean that this function should NOT be used if
|
|
|
|
+ * the RSS context flags might not be their defaults - it is ONLY
|
|
|
|
+ * reliably correct for a newly-allocated RSS context.
|
|
|
|
+ */
|
|
|
|
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_LEN);
|
|
|
|
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_LEN);
|
|
|
|
+ size_t outlen;
|
|
|
|
+ int rc;
|
|
|
|
+
|
|
|
|
+ /* Check we have a hole for the context ID */
|
|
|
|
+ BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_FLAGS_IN_LEN != MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_FLAGS_OFST);
|
|
|
|
+ MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_FLAGS_IN_RSS_CONTEXT_ID, context);
|
|
|
|
+ MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_FLAGS_OUT_FLAGS,
|
|
|
|
+ RSS_CONTEXT_FLAGS_DEFAULT);
|
|
|
|
+ rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_FLAGS, inbuf,
|
|
|
|
+ sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
|
|
|
|
+ if (rc == 0) {
|
|
|
|
+ if (outlen < MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_LEN)
|
|
|
|
+ rc = -EIO;
|
|
|
|
+ else
|
|
|
|
+ *flags = MCDI_DWORD(outbuf, RSS_CONTEXT_GET_FLAGS_OUT_FLAGS);
|
|
|
|
+ }
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Attempt to enable 4-tuple UDP hashing on the specified RSS context.
|
|
|
|
+ * If we fail, we just leave the RSS context at its default hash settings,
|
|
|
|
+ * which is safe but may slightly reduce performance.
|
|
|
|
+ * Defaults are 4-tuple for TCP and 2-tuple for UDP and other-IP, so we
|
|
|
|
+ * just need to set the UDP ports flags (for both IP versions).
|
|
|
|
+ */
|
|
|
|
+static void efx_ef10_set_rss_flags(struct efx_nic *efx, u32 context)
|
|
|
|
+{
|
|
|
|
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN);
|
|
|
|
+ u32 flags;
|
|
|
|
+
|
|
|
|
+ BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN != 0);
|
|
|
|
+
|
|
|
|
+ if (efx_ef10_get_rss_flags(efx, context, &flags) != 0)
|
|
|
|
+ return;
|
|
|
|
+ MCDI_SET_DWORD(inbuf, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID, context);
|
|
|
|
+ flags |= RSS_MODE_HASH_PORTS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV4_RSS_MODE_LBN;
|
|
|
|
+ flags |= RSS_MODE_HASH_PORTS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN;
|
|
|
|
+ MCDI_SET_DWORD(inbuf, RSS_CONTEXT_SET_FLAGS_IN_FLAGS, flags);
|
|
|
|
+ if (!efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_FLAGS, inbuf, sizeof(inbuf),
|
|
|
|
+ NULL, 0, NULL))
|
|
|
|
+ /* Succeeded, so UDP 4-tuple is now enabled */
|
|
|
|
+ efx->rx_hash_udp_4tuple = true;
|
|
|
|
+}
|
|
|
|
+
|
|
static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context,
|
|
static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context,
|
|
bool exclusive, unsigned *context_size)
|
|
bool exclusive, unsigned *context_size)
|
|
{
|
|
{
|
|
@@ -2290,6 +2370,10 @@ static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context,
|
|
if (context_size)
|
|
if (context_size)
|
|
*context_size = rss_spread;
|
|
*context_size = rss_spread;
|
|
|
|
|
|
|
|
+ if (nic_data->datapath_caps &
|
|
|
|
+ 1 << MC_CMD_GET_CAPABILITIES_OUT_ADDITIONAL_RSS_MODES_LBN)
|
|
|
|
+ efx_ef10_set_rss_flags(efx, *context);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|