Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49a67b5d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sfc-RX-hash-config'



Edward Cree says:

====================
sfc: RX hash configuration

This series improves support for getting and setting RX hashing
 configuration on Solarflare adapters through ethtool.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 96fe11f2 a707d188
Loading
Loading
Loading
Loading
+76 −8
Original line number Diff line number Diff line
@@ -1325,7 +1325,7 @@ static int efx_ef10_init_nic(struct efx_nic *efx)
	}

	/* 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;
@@ -2535,7 +2535,7 @@ static void efx_ef10_free_rss_context(struct efx_nic *efx, u32 context)
}

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);
@@ -2546,6 +2546,11 @@ static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context,
	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] =
@@ -2561,8 +2566,7 @@ static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context,
	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);
@@ -2595,7 +2599,8 @@ static int efx_ef10_rx_push_shared_rss_config(struct efx_nic *efx,
}

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;
@@ -2614,7 +2619,7 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
	}

	rc = efx_ef10_populate_rss_table(efx, new_rx_rss_context,
					 rx_indir_table);
					 rx_indir_table, key);
	if (rc != 0)
		goto fail2;

@@ -2625,6 +2630,9 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
	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:
@@ -2635,15 +2643,69 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
	return rc;
}

static int efx_ef10_rx_pull_rss_config(struct efx_nic *efx)
{
	struct efx_ef10_nic_data *nic_data = efx->nic_data;
	MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN);
	MCDI_DECLARE_BUF(tablebuf, MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_LEN);
	MCDI_DECLARE_BUF(keybuf, MC_CMD_RSS_CONTEXT_GET_KEY_OUT_LEN);
	size_t outlen;
	int rc, i;

	BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN !=
		     MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN);

	if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID)
		return -ENOENT;

	MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_TABLE_IN_RSS_CONTEXT_ID,
		       nic_data->rx_rss_context);
	BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) !=
		     MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE_LEN);
	rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_TABLE, inbuf, sizeof(inbuf),
			  tablebuf, sizeof(tablebuf), &outlen);
	if (rc != 0)
		return rc;

	if (WARN_ON(outlen != MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_LEN))
		return -EIO;

	for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
		efx->rx_indir_table[i] = MCDI_PTR(tablebuf,
				RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE)[i];

	MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_KEY_IN_RSS_CONTEXT_ID,
		       nic_data->rx_rss_context);
	BUILD_BUG_ON(ARRAY_SIZE(efx->rx_hash_key) !=
		     MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
	rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_KEY, inbuf, sizeof(inbuf),
			  keybuf, sizeof(keybuf), &outlen);
	if (rc != 0)
		return rc;

	if (WARN_ON(outlen != MC_CMD_RSS_CONTEXT_GET_KEY_OUT_LEN))
		return -EIO;

	for (i = 0; i < ARRAY_SIZE(efx->rx_hash_key); ++i)
		efx->rx_hash_key[i] = MCDI_PTR(
				keybuf, RSS_CONTEXT_GET_KEY_OUT_TOEPLITZ_KEY)[i];

	return 0;
}

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;
@@ -2681,6 +2743,8 @@ static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user,

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;
@@ -5629,6 +5693,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
	.tx_write = efx_ef10_tx_write,
	.tx_limit_len = efx_ef10_tx_limit_len,
	.rx_push_rss_config = efx_ef10_vf_rx_push_rss_config,
	.rx_pull_rss_config = efx_ef10_rx_pull_rss_config,
	.rx_probe = efx_ef10_rx_probe,
	.rx_init = efx_ef10_rx_init,
	.rx_remove = efx_ef10_rx_remove,
@@ -5686,6 +5751,7 @@ const struct efx_nic_type efx_hunt_a0_vf_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,
};

const struct efx_nic_type efx_hunt_a0_nic_type = {
@@ -5736,6 +5802,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
	.tx_write = efx_ef10_tx_write,
	.tx_limit_len = efx_ef10_tx_limit_len,
	.rx_push_rss_config = efx_ef10_pf_rx_push_rss_config,
	.rx_pull_rss_config = efx_ef10_rx_pull_rss_config,
	.rx_probe = efx_ef10_rx_probe,
	.rx_init = efx_ef10_rx_init,
	.rx_remove = efx_ef10_rx_remove,
@@ -5812,4 +5879,5 @@ 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,
};
+24 −5
Original line number Diff line number Diff line
@@ -1278,15 +1278,29 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
	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)
{
	struct efx_nic *efx = netdev_priv(net_dev);
	int rc;

	rc = efx->type->rx_pull_rss_config(efx);
	if (rc)
		return rc;

	if (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;
}

@@ -1295,14 +1309,18 @@ static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
{
	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,
@@ -1377,6 +1395,7 @@ const struct ethtool_ops efx_ethtool_ops = {
	.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,
+16 −0
Original line number Diff line number Diff line
@@ -1649,6 +1649,22 @@ void efx_farch_rx_push_indir_table(struct efx_nic *efx)
	}
}

void efx_farch_rx_pull_indir_table(struct efx_nic *efx)
{
	size_t i = 0;
	efx_dword_t dword;

	BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) !=
		     FR_BZ_RX_INDIRECTION_TBL_ROWS);

	for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) {
		efx_readd(efx, &dword,
			   FR_BZ_RX_INDIRECTION_TBL +
			   FR_BZ_RX_INDIRECTION_TBL_STEP * i);
		efx->rx_indir_table[i] = EFX_DWORD_FIELD(dword, FRF_BZ_IT_QUEUE);
	}
}

/* Looks at available SRAM resources and works out how many queues we
 * can support, and where things like descriptor caches should live.
 *
+4 −1
Original line number Diff line number Diff line
@@ -1181,6 +1181,7 @@ struct efx_mtd_partition {
 * @tx_remove: Free resources for TX queue
 * @tx_write: Write TX descriptors and doorbell
 * @rx_push_rss_config: Write RSS hash key and indirection table to the NIC
 * @rx_pull_rss_config: Read RSS hash key and indirection table back from the NIC
 * @rx_probe: Allocate resources for RX queue
 * @rx_init: Initialise RX queue on the NIC
 * @rx_remove: Free resources for RX queue
@@ -1311,7 +1312,8 @@ struct efx_nic_type {
	unsigned int (*tx_limit_len)(struct efx_tx_queue *tx_queue,
				     dma_addr_t dma_addr, unsigned int len);
	int (*rx_push_rss_config)(struct efx_nic *efx, bool user,
				  const u32 *rx_indir_table);
				  const u32 *rx_indir_table, const u8 *key);
	int (*rx_pull_rss_config)(struct efx_nic *efx);
	int (*rx_probe)(struct efx_rx_queue *rx_queue);
	void (*rx_init)(struct efx_rx_queue *rx_queue);
	void (*rx_remove)(struct efx_rx_queue *rx_queue);
@@ -1410,6 +1412,7 @@ struct efx_nic_type {
	int mcdi_max_ver;
	unsigned int max_rx_ip_filters;
	u32 hwtstamp_filters;
	unsigned int rx_hash_key_size;
};

/**************************************************************************
+1 −0
Original line number Diff line number Diff line
@@ -626,6 +626,7 @@ void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw);
void efx_farch_init_common(struct efx_nic *efx);
void efx_ef10_handle_drain_event(struct efx_nic *efx);
void efx_farch_rx_push_indir_table(struct efx_nic *efx);
void efx_farch_rx_pull_indir_table(struct efx_nic *efx);

int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
			 unsigned int len, gfp_t gfp_flags);
Loading