}
 
        /* don't fail init if RSS setup doesn't work */
-       rc = efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table);
+       rc = efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table, NULL);
        efx->rss_active = (rc == 0);
 
        return 0;
 }
 
 static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context,
-                                      const u32 *rx_indir_table)
+                                      const u32 *rx_indir_table, const u8 *key)
 {
        MCDI_DECLARE_BUF(tablebuf, MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN);
        MCDI_DECLARE_BUF(keybuf, MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN);
        BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) !=
                     MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN);
 
+       /* This iterates over the length of efx->rx_indir_table, but copies
+        * bytes from rx_indir_table.  That's because the latter is a pointer
+        * rather than an array, but should have the same length.
+        * The efx->rx_hash_key loop below is similar.
+        */
        for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); ++i)
                MCDI_PTR(tablebuf,
                         RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE)[i] =
        BUILD_BUG_ON(ARRAY_SIZE(efx->rx_hash_key) !=
                     MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
        for (i = 0; i < ARRAY_SIZE(efx->rx_hash_key); ++i)
-               MCDI_PTR(keybuf, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY)[i] =
-                       efx->rx_hash_key[i];
+               MCDI_PTR(keybuf, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY)[i] = key[i];
 
        return efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_KEY, keybuf,
                            sizeof(keybuf), NULL, 0, NULL);
 }
 
 static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
-                                                const u32 *rx_indir_table)
+                                                const u32 *rx_indir_table,
+                                                const u8 *key)
 {
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
        int rc;
        }
 
        rc = efx_ef10_populate_rss_table(efx, new_rx_rss_context,
-                                        rx_indir_table);
+                                        rx_indir_table, key);
        if (rc != 0)
                goto fail2;
 
        if (rx_indir_table != efx->rx_indir_table)
                memcpy(efx->rx_indir_table, rx_indir_table,
                       sizeof(efx->rx_indir_table));
+       if (key != efx->rx_hash_key)
+               memcpy(efx->rx_hash_key, key, efx->type->rx_hash_key_size);
+
        return 0;
 
 fail2:
 }
 
 static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user,
-                                         const u32 *rx_indir_table)
+                                         const u32 *rx_indir_table,
+                                         const u8 *key)
 {
        int rc;
 
        if (efx->rss_spread == 1)
                return 0;
 
-       rc = efx_ef10_rx_push_exclusive_rss_config(efx, rx_indir_table);
+       if (!key)
+               key = efx->rx_hash_key;
+
+       rc = efx_ef10_rx_push_exclusive_rss_config(efx, rx_indir_table, key);
 
        if (rc == -ENOBUFS && !user) {
                unsigned context_size;
 
 static int efx_ef10_vf_rx_push_rss_config(struct efx_nic *efx, bool user,
                                          const u32 *rx_indir_table
+                                         __attribute__ ((unused)),
+                                         const u8 *key
                                          __attribute__ ((unused)))
 {
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
        .max_rx_ip_filters = HUNT_FILTER_TBL_ROWS,
        .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE |
                            1 << HWTSTAMP_FILTER_ALL,
+       .rx_hash_key_size = 40,
 };
 
 const struct efx_nic_type efx_hunt_a0_nic_type = {
        .max_rx_ip_filters = HUNT_FILTER_TBL_ROWS,
        .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE |
                            1 << HWTSTAMP_FILTER_ALL,
+       .rx_hash_key_size = 40,
 };
 
        return (efx->n_rx_channels == 1) ? 0 : ARRAY_SIZE(efx->rx_indir_table);
 }
 
+static u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+
+       return efx->type->rx_hash_key_size;
+}
+
 static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
                                u8 *hfunc)
 {
                *hfunc = ETH_RSS_HASH_TOP;
        if (indir)
                memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
+       if (key)
+               memcpy(key, efx->rx_hash_key, efx->type->rx_hash_key_size);
        return 0;
 }
 
 {
        struct efx_nic *efx = netdev_priv(net_dev);
 
-       /* We do not allow change in unsupported parameters */
-       if (key ||
-           (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+       /* Hash function is Toeplitz, cannot be changed */
+       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
                return -EOPNOTSUPP;
-       if (!indir)
+       if (!indir && !key)
                return 0;
 
-       return efx->type->rx_push_rss_config(efx, true, indir);
+       if (!key)
+               key = efx->rx_hash_key;
+       if (!indir)
+               indir = efx->rx_indir_table;
+
+       return efx->type->rx_push_rss_config(efx, true, indir, key);
 }
 
 static int efx_ethtool_get_ts_info(struct net_device *net_dev,
        .get_rxnfc              = efx_ethtool_get_rxnfc,
        .set_rxnfc              = efx_ethtool_set_rxnfc,
        .get_rxfh_indir_size    = efx_ethtool_get_rxfh_indir_size,
+       .get_rxfh_key_size      = efx_ethtool_get_rxfh_key_size,
        .get_rxfh               = efx_ethtool_get_rxfh,
        .set_rxfh               = efx_ethtool_set_rxfh,
        .get_ts_info            = efx_ethtool_get_ts_info,
 
 }
 
 static int siena_rx_push_rss_config(struct efx_nic *efx, bool user,
-                                   const u32 *rx_indir_table)
+                                   const u32 *rx_indir_table, const u8 *key)
 {
        efx_oword_t temp;
 
        /* Set hash key for IPv4 */
+       if (key)
+               memcpy(efx->rx_hash_key, key, sizeof(temp));
        memcpy(&temp, efx->rx_hash_key, sizeof(temp));
        efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
 
                            EFX_RX_USR_BUF_SIZE >> 5);
        efx_writeo(efx, &temp, FR_AZ_RX_CFG);
 
-       siena_rx_push_rss_config(efx, false, efx->rx_indir_table);
+       siena_rx_push_rss_config(efx, false, efx->rx_indir_table, NULL);
        efx->rss_active = true;
 
        /* Enable event logging */
        .hwtstamp_filters = (1 << HWTSTAMP_FILTER_NONE |
                             1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT |
                             1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT),
+       .rx_hash_key_size = 16,
 };