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

Commit 2c86ac3c authored by Helin Zhang's avatar Helin Zhang Committed by Jeff Kirsher
Browse files

i40evf: create a generic config RSS function



There are two ways to configure RSS, this patch adjusts those two
functions with the same input parameters, and creates a more
generic function for configuring RSS.

Change-ID: Iace73bdeba4831909979bef221011060ab327f71
Signed-off-by: default avatarHelin Zhang <helin.zhang@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 96a81986
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -99,6 +99,7 @@ struct i40e_vsi {
#define MAX_TX_QUEUES MAX_RX_QUEUES
#define MAX_TX_QUEUES MAX_RX_QUEUES


#define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4)
#define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4)
#define I40EVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4)


/* MAX_MSIX_Q_VECTORS of these are allocated,
/* MAX_MSIX_Q_VECTORS of these are allocated,
 * but we only use one per queue-specific vector.
 * but we only use one per queue-specific vector.
@@ -313,4 +314,6 @@ void i40evf_request_reset(struct i40evf_adapter *adapter);
void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
				enum i40e_virtchnl_ops v_opcode,
				enum i40e_virtchnl_ops v_opcode,
				i40e_status v_retval, u8 *msg, u16 msglen);
				i40e_status v_retval, u8 *msg, u16 msglen);
int i40evf_config_rss(struct i40e_vsi *vsi, const u8 *seed, u8 *lut,
		      u16 lut_size);
#endif /* _I40EVF_H_ */
#endif /* _I40EVF_H_ */
+19 −10
Original line number Original line Diff line number Diff line
@@ -668,9 +668,11 @@ static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
			   const u8 *key, const u8 hfunc)
			   const u8 *key, const u8 hfunc)
{
{
	struct i40evf_adapter *adapter = netdev_priv(netdev);
	struct i40evf_adapter *adapter = netdev_priv(netdev);
	struct i40e_hw *hw = &adapter->hw;
	struct i40e_vsi *vsi = &adapter->vsi;
	u32 hlut_val;
	u8 seed_def[I40EVF_HKEY_ARRAY_SIZE];
	int i, j;
	u8 *seed = NULL, *lut;
	int ret;
	u16 i;


	/* We do not allow change in unsupported parameters */
	/* We do not allow change in unsupported parameters */
	if (key ||
	if (key ||
@@ -679,15 +681,22 @@ static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
	if (!indir)
	if (!indir)
		return 0;
		return 0;


	for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
	if (key) {
		hlut_val = indir[j++];
		memcpy(seed_def, key, I40EVF_HKEY_ARRAY_SIZE);
		hlut_val |= indir[j++] << 8;
		seed = seed_def;
		hlut_val |= indir[j++] << 16;
		hlut_val |= indir[j++] << 24;
		wr32(hw, I40E_VFQF_HLUT(i), hlut_val);
	}
	}
	lut = kzalloc(I40EVF_HLUT_ARRAY_SIZE, GFP_KERNEL);
	if (!lut)
		return -ENOMEM;


	return 0;
	/* Each 32 bits pointed by 'indir' is stored with a lut entry */
	for (i = 0; i < I40EVF_HLUT_ARRAY_SIZE; i++)
		lut[i] = (u8)(indir[i]);

	ret = i40evf_config_rss(vsi, seed, lut, I40EVF_HLUT_ARRAY_SIZE);
	kfree(lut);

	return ret;
}
}


static const struct ethtool_ops i40evf_ethtool_ops = {
static const struct ethtool_ops i40evf_ethtool_ops = {
+108 −60
Original line number Original line Diff line number Diff line
@@ -1211,110 +1211,158 @@ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter)
}
}


/**
/**
 * i40e_configure_rss_aq - Prepare for RSS using AQ commands
 * i40e_config_rss_aq - Prepare for RSS using AQ commands
 * @vsi: vsi structure
 * @vsi: vsi structure
 * @seed: RSS hash seed
 * @seed: RSS hash seed
 * @lut: Lookup table
 * @lut_size: Lookup table size
 *
 * Return 0 on success, negative on failure
 **/
 **/
static void i40evf_configure_rss_aq(struct i40e_vsi *vsi, const u8 *seed)
static int i40evf_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
				u8 *lut, u16 lut_size)
{
{
	struct i40e_aqc_get_set_rss_key_data rss_key;
	struct i40evf_adapter *adapter = vsi->back;
	struct i40evf_adapter *adapter = vsi->back;
	struct i40e_hw *hw = &adapter->hw;
	struct i40e_hw *hw = &adapter->hw;
	int ret = 0, i;
	int ret = 0;
	u8 *rss_lut;


	if (!vsi->id)
	if (!vsi->id)
		return;
		return -EINVAL;


	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
		/* bail because we already have a command pending */
		/* bail because we already have a command pending */
		dev_err(&adapter->pdev->dev, "Cannot confiure RSS, command %d pending\n",
		dev_err(&adapter->pdev->dev, "Cannot confiure RSS, command %d pending\n",
			adapter->current_op);
			adapter->current_op);
		return;
		return -EBUSY;
	}
	}


	memset(&rss_key, 0, sizeof(rss_key));
	if (seed) {
	memcpy(&rss_key, seed, sizeof(rss_key));
		struct i40e_aqc_get_set_rss_key_data *rss_key =

			(struct i40e_aqc_get_set_rss_key_data *)seed;
	rss_lut = kzalloc(((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4), GFP_KERNEL);
		ret = i40evf_aq_set_rss_key(hw, vsi->id, rss_key);
	if (!rss_lut)
		return;

	/* Populate the LUT with max no. PF queues in round robin fashion */
	for (i = 0; i <= (I40E_VFQF_HLUT_MAX_INDEX * 4); i++)
		rss_lut[i] = i % adapter->num_active_queues;

	ret = i40evf_aq_set_rss_key(hw, vsi->id, &rss_key);
		if (ret) {
		if (ret) {
		dev_err(&adapter->pdev->dev,
			dev_err(&adapter->pdev->dev, "Cannot set RSS key, err %s aq_err %s\n",
			"Cannot set RSS key, err %s aq_err %s\n",
				i40evf_stat_str(hw, ret),
				i40evf_stat_str(hw, ret),
				i40evf_aq_str(hw, hw->aq.asq_last_status));
				i40evf_aq_str(hw, hw->aq.asq_last_status));
		return;
			return ret;
		}
	}
	}


	ret = i40evf_aq_set_rss_lut(hw, vsi->id, false, rss_lut,
	if (lut) {
				    (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4);
		ret = i40evf_aq_set_rss_lut(hw, vsi->id, false, lut, lut_size);
	if (ret)
		if (ret) {
			dev_err(&adapter->pdev->dev,
			dev_err(&adapter->pdev->dev,
				"Cannot set RSS lut, err %s aq_err %s\n",
				"Cannot set RSS lut, err %s aq_err %s\n",
				i40evf_stat_str(hw, ret),
				i40evf_stat_str(hw, ret),
				i40evf_aq_str(hw, hw->aq.asq_last_status));
				i40evf_aq_str(hw, hw->aq.asq_last_status));
			return ret;
		}
	}

	return ret;
}
}


/**
/**
 * i40e_configure_rss_reg - Prepare for RSS if used
 * i40evf_config_rss_reg - Configure RSS keys and lut by writing registers
 * @adapter: board private structure
 * @vsi: Pointer to vsi structure
 * @seed: RSS hash seed
 * @seed: RSS hash seed
 * @lut: Lookup table
 * @lut_size: Lookup table size
 *
 * Returns 0 on success, negative on failure
 **/
 **/
static void i40evf_configure_rss_reg(struct i40evf_adapter *adapter,
static int i40evf_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
				     const u8 *seed)
				 const u8 *lut, u16 lut_size)
{
{
	struct i40evf_adapter *adapter = vsi->back;
	struct i40e_hw *hw = &adapter->hw;
	struct i40e_hw *hw = &adapter->hw;
	u16 i;

	if (seed) {
		u32 *seed_dw = (u32 *)seed;
		u32 *seed_dw = (u32 *)seed;
	u32 cqueue = 0;
	u32 lut = 0;
	int i, j;


	/* Fill out hash function seed */
		for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
		for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
			wr32(hw, I40E_VFQF_HKEY(i), seed_dw[i]);
			wr32(hw, I40E_VFQF_HKEY(i), seed_dw[i]);

	/* Populate the LUT with max no. PF queues in round robin fashion */
	for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
		lut = 0;
		for (j = 0; j < 4; j++) {
			if (cqueue == adapter->num_active_queues)
				cqueue = 0;
			lut |= ((cqueue) << (8 * j));
			cqueue++;
	}
	}
		wr32(hw, I40E_VFQF_HLUT(i), lut);

	if (lut) {
		u32 *lut_dw = (u32 *)lut;

		if (lut_size != I40EVF_HLUT_ARRAY_SIZE)
			return -EINVAL;

		for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++)
			wr32(hw, I40E_VFQF_HLUT(i), lut_dw[i]);
	}
	}
	i40e_flush(hw);
	i40e_flush(hw);

	return 0;
}

/**
 * i40evf_config_rss - Configure RSS keys and lut
 * @vsi: Pointer to vsi structure
 * @seed: RSS hash seed
 * @lut: Lookup table
 * @lut_size: Lookup table size
 *
 * Returns 0 on success, negative on failure
 **/
int i40evf_config_rss(struct i40e_vsi *vsi, const u8 *seed,
		      u8 *lut, u16 lut_size)
{
	struct i40evf_adapter *adapter = vsi->back;

	if (RSS_AQ(adapter))
		return i40evf_config_rss_aq(vsi, seed, lut, lut_size);
	else
		return i40evf_config_rss_reg(vsi, seed, lut, lut_size);
}

/**
 * i40evf_fill_rss_lut - Fill the lut with default values
 * @lut: Lookup table to be filled with
 * @rss_table_size: Lookup table size
 * @rss_size: Range of queue number for hashing
 **/
static void i40evf_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size)
{
	u16 i;

	for (i = 0; i < rss_table_size; i++)
		lut[i] = i % rss_size;
}
}


/**
/**
 * i40evf_init_rss - Prepare for RSS
 * i40evf_init_rss - Prepare for RSS
 * @adapter: board private structure
 * @adapter: board private structure
 *
 * Return 0 on success, negative on failure
 **/
 **/
static void i40evf_init_rss(struct i40evf_adapter *adapter)
static int i40evf_init_rss(struct i40evf_adapter *adapter)
{
{
	struct i40e_vsi *vsi = &adapter->vsi;
	struct i40e_hw *hw = &adapter->hw;
	struct i40e_hw *hw = &adapter->hw;
	u8 seed[I40EVF_HKEY_ARRAY_SIZE];
	u8 seed[I40EVF_HKEY_ARRAY_SIZE];
	u64 hena;
	u64 hena;

	u8 *lut;
	netdev_rss_key_fill((void *)seed, I40EVF_HKEY_ARRAY_SIZE);
	int ret;


	/* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */
	/* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */
	hena = I40E_DEFAULT_RSS_HENA;
	hena = I40E_DEFAULT_RSS_HENA;
	wr32(hw, I40E_VFQF_HENA(0), (u32)hena);
	wr32(hw, I40E_VFQF_HENA(0), (u32)hena);
	wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
	wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));


	if (RSS_AQ(adapter))
	lut = kzalloc(I40EVF_HLUT_ARRAY_SIZE, GFP_KERNEL);
		i40evf_configure_rss_aq(&adapter->vsi, seed);
	if (!lut)
	else
		return -ENOMEM;
		i40evf_configure_rss_reg(adapter, seed);
	i40evf_fill_rss_lut(lut, I40EVF_HLUT_ARRAY_SIZE,
			    adapter->num_active_queues);
	netdev_rss_key_fill((void *)seed, I40EVF_HKEY_ARRAY_SIZE);
	ret = i40evf_config_rss(vsi, seed, lut, I40EVF_HLUT_ARRAY_SIZE);
	kfree(lut);

	return ret;
}
}


/**
/**