mirror of https://gitee.com/openkylin/linux.git
ethtool: Support for configurable RSS hash function
This patch extends the set/get_rxfh ethtool-options for getting or setting the RSS hash function. It modifies drivers implementation of set/get_rxfh accordingly. This change also delegates the responsibility of checking whether a modification to a certain RX flow hash parameter is supported to the driver implementation of set_rxfh. User-kernel API is done through the new hfunc bitmask field in the ethtool_rxfh struct. A bit set in the hfunc field is corresponding to an index in the new string-set ETH_SS_RSS_HASH_FUNCS. Got approval from most of the relevant driver maintainers that their driver is using Toeplitz, and for the few that didn't answered, also assumed it is Toeplitz. Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Ariel Elior <ariel.elior@qlogic.com> Cc: Prashant Sreedharan <prashant@broadcom.com> Cc: Michael Chan <mchan@broadcom.com> Cc: Hariprasad S <hariprasad@chelsio.com> Cc: Sathya Perla <sathya.perla@emulex.com> Cc: Subbu Seetharaman <subbu.seetharaman@emulex.com> Cc: Ajit Khaparde <ajit.khaparde@emulex.com> Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Cc: Jesse Brandeburg <jesse.brandeburg@intel.com> Cc: Bruce Allan <bruce.w.allan@intel.com> Cc: Carolyn Wyborny <carolyn.wyborny@intel.com> Cc: Don Skidmore <donald.c.skidmore@intel.com> Cc: Greg Rose <gregory.v.rose@intel.com> Cc: Matthew Vick <matthew.vick@intel.com> Cc: John Ronciak <john.ronciak@intel.com> Cc: Mitch Williams <mitch.a.williams@intel.com> Cc: Amir Vadai <amirv@mellanox.com> Cc: Solarflare linux maintainers <linux-net-drivers@solarflare.com> Cc: Shradha Shah <sshah@solarflare.com> Cc: Shreyas Bhatewara <sbhatewara@vmware.com> Cc: "VMware, Inc." <pv-drivers@vmware.com> Cc: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Eyal Perry <eyalpe@mellanox.com> Signed-off-by: Amir Vadai <amirv@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
18b5427ae1
commit
892311f66f
|
@ -511,7 +511,8 @@ static u32 xgbe_get_rxfh_indir_size(struct net_device *netdev)
|
||||||
return ARRAY_SIZE(pdata->rss_table);
|
return ARRAY_SIZE(pdata->rss_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
|
static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
||||||
|
u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -525,16 +526,22 @@ static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
|
||||||
if (key)
|
if (key)
|
||||||
memcpy(key, pdata->rss_key, sizeof(pdata->rss_key));
|
memcpy(key, pdata->rss_key, sizeof(pdata->rss_key));
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
|
static int xgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
|
||||||
const u8 *key)
|
const u8 *key, const u8 hfunc)
|
||||||
{
|
{
|
||||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||||
unsigned int ret;
|
unsigned int ret;
|
||||||
|
|
||||||
|
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (indir) {
|
if (indir) {
|
||||||
ret = hw_if->set_rss_lookup_table(pdata, indir);
|
ret = hw_if->set_rss_lookup_table(pdata, indir);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
@ -3358,12 +3358,18 @@ static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev)
|
||||||
return T_ETH_INDIRECTION_TABLE_SIZE;
|
return T_ETH_INDIRECTION_TABLE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key)
|
static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
|
||||||
|
u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct bnx2x *bp = netdev_priv(dev);
|
struct bnx2x *bp = netdev_priv(dev);
|
||||||
u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
|
u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Get the current configuration of the RSS indirection table */
|
/* Get the current configuration of the RSS indirection table */
|
||||||
bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table);
|
bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table);
|
||||||
|
|
||||||
|
@ -3383,11 +3389,21 @@ static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir,
|
static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir,
|
||||||
const u8 *key)
|
const u8 *key, const u8 hfunc)
|
||||||
{
|
{
|
||||||
struct bnx2x *bp = netdev_priv(dev);
|
struct bnx2x *bp = netdev_priv(dev);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
/* We require at least one supported parameter to be changed and no
|
||||||
|
* change in any of the unsupported parameters
|
||||||
|
*/
|
||||||
|
if (key ||
|
||||||
|
(hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
|
for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
|
||||||
/*
|
/*
|
||||||
* The same as in bnx2x_get_rxfh: we can't use a memcpy()
|
* The same as in bnx2x_get_rxfh: we can't use a memcpy()
|
||||||
|
|
|
@ -12561,22 +12561,38 @@ static u32 tg3_get_rxfh_indir_size(struct net_device *dev)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key)
|
static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct tg3 *tp = netdev_priv(dev);
|
struct tg3 *tp = netdev_priv(dev);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
|
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
|
||||||
indir[i] = tp->rss_ind_tbl[i];
|
indir[i] = tp->rss_ind_tbl[i];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key)
|
static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key,
|
||||||
|
const u8 hfunc)
|
||||||
{
|
{
|
||||||
struct tg3 *tp = netdev_priv(dev);
|
struct tg3 *tp = netdev_priv(dev);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
/* We require at least one supported parameter to be changed and no
|
||||||
|
* change in any of the unsupported parameters
|
||||||
|
*/
|
||||||
|
if (key ||
|
||||||
|
(hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
|
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
|
||||||
tp->rss_ind_tbl[i] = indir[i];
|
tp->rss_ind_tbl[i] = indir[i];
|
||||||
|
|
||||||
|
|
|
@ -2923,21 +2923,35 @@ static u32 get_rss_table_size(struct net_device *dev)
|
||||||
return pi->rss_size;
|
return pi->rss_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_rss_table(struct net_device *dev, u32 *p, u8 *key)
|
static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc)
|
||||||
{
|
{
|
||||||
const struct port_info *pi = netdev_priv(dev);
|
const struct port_info *pi = netdev_priv(dev);
|
||||||
unsigned int n = pi->rss_size;
|
unsigned int n = pi->rss_size;
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
if (!p)
|
||||||
|
return 0;
|
||||||
while (n--)
|
while (n--)
|
||||||
p[n] = pi->rss[n];
|
p[n] = pi->rss[n];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key)
|
static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key,
|
||||||
|
const u8 hfunc)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct port_info *pi = netdev_priv(dev);
|
struct port_info *pi = netdev_priv(dev);
|
||||||
|
|
||||||
|
/* We require at least one supported parameter to be changed and no
|
||||||
|
* change in any of the unsupported parameters
|
||||||
|
*/
|
||||||
|
if (key ||
|
||||||
|
(hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!p)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < pi->rss_size; i++)
|
for (i = 0; i < pi->rss_size; i++)
|
||||||
pi->rss[i] = p[i];
|
pi->rss[i] = p[i];
|
||||||
if (pi->adapter->flags & FULL_INIT_DONE)
|
if (pi->adapter->flags & FULL_INIT_DONE)
|
||||||
|
|
|
@ -1171,7 +1171,8 @@ static u32 be_get_rxfh_key_size(struct net_device *netdev)
|
||||||
return RSS_HASH_KEY_LEN;
|
return RSS_HASH_KEY_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey)
|
static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey,
|
||||||
|
u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct be_adapter *adapter = netdev_priv(netdev);
|
struct be_adapter *adapter = netdev_priv(netdev);
|
||||||
int i;
|
int i;
|
||||||
|
@ -1185,16 +1186,23 @@ static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey)
|
||||||
if (hkey)
|
if (hkey)
|
||||||
memcpy(hkey, rss->rss_hkey, RSS_HASH_KEY_LEN);
|
memcpy(hkey, rss->rss_hkey, RSS_HASH_KEY_LEN);
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int be_set_rxfh(struct net_device *netdev, const u32 *indir,
|
static int be_set_rxfh(struct net_device *netdev, const u32 *indir,
|
||||||
const u8 *hkey)
|
const u8 *hkey, const u8 hfunc)
|
||||||
{
|
{
|
||||||
int rc = 0, i, j;
|
int rc = 0, i, j;
|
||||||
struct be_adapter *adapter = netdev_priv(netdev);
|
struct be_adapter *adapter = netdev_priv(netdev);
|
||||||
u8 rsstable[RSS_INDIR_TABLE_LEN];
|
u8 rsstable[RSS_INDIR_TABLE_LEN];
|
||||||
|
|
||||||
|
/* We do not allow change in unsupported parameters */
|
||||||
|
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (indir) {
|
if (indir) {
|
||||||
struct be_rx_obj *rxo;
|
struct be_rx_obj *rxo;
|
||||||
|
|
||||||
|
|
|
@ -916,11 +916,15 @@ static u32 fm10k_get_rssrk_size(struct net_device *netdev)
|
||||||
return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG;
|
return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key)
|
static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key,
|
||||||
|
u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct fm10k_intfc *interface = netdev_priv(netdev);
|
struct fm10k_intfc *interface = netdev_priv(netdev);
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
|
||||||
err = fm10k_get_reta(netdev, indir);
|
err = fm10k_get_reta(netdev, indir);
|
||||||
if (err || !key)
|
if (err || !key)
|
||||||
return err;
|
return err;
|
||||||
|
@ -932,12 +936,16 @@ static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fm10k_set_rssh(struct net_device *netdev, const u32 *indir,
|
static int fm10k_set_rssh(struct net_device *netdev, const u32 *indir,
|
||||||
const u8 *key)
|
const u8 *key, const u8 hfunc)
|
||||||
{
|
{
|
||||||
struct fm10k_intfc *interface = netdev_priv(netdev);
|
struct fm10k_intfc *interface = netdev_priv(netdev);
|
||||||
struct fm10k_hw *hw = &interface->hw;
|
struct fm10k_hw *hw = &interface->hw;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
|
/* We do not allow change in unsupported parameters */
|
||||||
|
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
err = fm10k_set_reta(netdev, indir);
|
err = fm10k_set_reta(netdev, indir);
|
||||||
if (err || !key)
|
if (err || !key)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -627,13 +627,19 @@ static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev)
|
||||||
*
|
*
|
||||||
* Reads the indirection table directly from the hardware. Always returns 0.
|
* Reads the indirection table directly from the hardware. Always returns 0.
|
||||||
**/
|
**/
|
||||||
static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
|
static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
||||||
|
u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct i40evf_adapter *adapter = netdev_priv(netdev);
|
struct i40evf_adapter *adapter = netdev_priv(netdev);
|
||||||
struct i40e_hw *hw = &adapter->hw;
|
struct i40e_hw *hw = &adapter->hw;
|
||||||
u32 hlut_val;
|
u32 hlut_val;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
|
for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
|
||||||
hlut_val = rd32(hw, I40E_VFQF_HLUT(i));
|
hlut_val = rd32(hw, I40E_VFQF_HLUT(i));
|
||||||
indir[j++] = hlut_val & 0xff;
|
indir[j++] = hlut_val & 0xff;
|
||||||
|
@ -654,13 +660,20 @@ static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
|
||||||
* returns 0 after programming the table.
|
* returns 0 after programming the table.
|
||||||
**/
|
**/
|
||||||
static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
|
static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
|
||||||
const u8 *key)
|
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_hw *hw = &adapter->hw;
|
||||||
u32 hlut_val;
|
u32 hlut_val;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
|
/* We do not allow change in unsupported parameters */
|
||||||
|
if (key ||
|
||||||
|
(hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
|
for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
|
||||||
hlut_val = indir[j++];
|
hlut_val = indir[j++];
|
||||||
hlut_val |= indir[j++] << 8;
|
hlut_val |= indir[j++] << 8;
|
||||||
|
|
|
@ -2842,11 +2842,16 @@ static u32 igb_get_rxfh_indir_size(struct net_device *netdev)
|
||||||
return IGB_RETA_SIZE;
|
return IGB_RETA_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
|
static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
||||||
|
u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
for (i = 0; i < IGB_RETA_SIZE; i++)
|
for (i = 0; i < IGB_RETA_SIZE; i++)
|
||||||
indir[i] = adapter->rss_indir_tbl[i];
|
indir[i] = adapter->rss_indir_tbl[i];
|
||||||
|
|
||||||
|
@ -2889,13 +2894,20 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int igb_set_rxfh(struct net_device *netdev, const u32 *indir,
|
static int igb_set_rxfh(struct net_device *netdev, const u32 *indir,
|
||||||
const u8 *key)
|
const u8 *key, const u8 hfunc)
|
||||||
{
|
{
|
||||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||||
struct e1000_hw *hw = &adapter->hw;
|
struct e1000_hw *hw = &adapter->hw;
|
||||||
int i;
|
int i;
|
||||||
u32 num_queues;
|
u32 num_queues;
|
||||||
|
|
||||||
|
/* We do not allow change in unsupported parameters */
|
||||||
|
if (key ||
|
||||||
|
(hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
num_queues = adapter->rss_queues;
|
num_queues = adapter->rss_queues;
|
||||||
|
|
||||||
switch (hw->mac.type) {
|
switch (hw->mac.type) {
|
||||||
|
|
|
@ -978,7 +978,8 @@ static u32 mlx4_en_get_rxfh_key_size(struct net_device *netdev)
|
||||||
return MLX4_EN_RSS_KEY_SIZE;
|
return MLX4_EN_RSS_KEY_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key)
|
static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key,
|
||||||
|
u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||||
struct mlx4_en_rss_map *rss_map = &priv->rss_map;
|
struct mlx4_en_rss_map *rss_map = &priv->rss_map;
|
||||||
|
@ -990,16 +991,20 @@ static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key)
|
||||||
rss_rings = 1 << ilog2(rss_rings);
|
rss_rings = 1 << ilog2(rss_rings);
|
||||||
|
|
||||||
while (n--) {
|
while (n--) {
|
||||||
|
if (!ring_index)
|
||||||
|
break;
|
||||||
ring_index[n] = rss_map->qps[n % rss_rings].qpn -
|
ring_index[n] = rss_map->qps[n % rss_rings].qpn -
|
||||||
rss_map->base_qpn;
|
rss_map->base_qpn;
|
||||||
}
|
}
|
||||||
if (key)
|
if (key)
|
||||||
memcpy(key, priv->rss_key, MLX4_EN_RSS_KEY_SIZE);
|
memcpy(key, priv->rss_key, MLX4_EN_RSS_KEY_SIZE);
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
|
static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
|
||||||
const u8 *key)
|
const u8 *key, const u8 hfunc)
|
||||||
{
|
{
|
||||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||||
struct mlx4_en_dev *mdev = priv->mdev;
|
struct mlx4_en_dev *mdev = priv->mdev;
|
||||||
|
@ -1008,6 +1013,10 @@ static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
|
||||||
int i;
|
int i;
|
||||||
int rss_rings = 0;
|
int rss_rings = 0;
|
||||||
|
|
||||||
|
/* We do not allow change in unsupported parameters */
|
||||||
|
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
/* Calculate RSS table size and make sure flows are spread evenly
|
/* Calculate RSS table size and make sure flows are spread evenly
|
||||||
* between rings
|
* between rings
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1086,19 +1086,29 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
|
||||||
0 : ARRAY_SIZE(efx->rx_indir_table));
|
0 : ARRAY_SIZE(efx->rx_indir_table));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key)
|
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);
|
struct efx_nic *efx = netdev_priv(net_dev);
|
||||||
|
|
||||||
memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
if (indir)
|
||||||
|
memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int efx_ethtool_set_rxfh(struct net_device *net_dev,
|
static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
|
||||||
const u32 *indir, const u8 *key)
|
const u8 *key, const u8 hfunc)
|
||||||
{
|
{
|
||||||
struct efx_nic *efx = netdev_priv(net_dev);
|
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))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table));
|
memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table));
|
||||||
efx->type->rx_push_rss_config(efx);
|
efx->type->rx_push_rss_config(efx);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -583,12 +583,16 @@ vmxnet3_get_rss_indir_size(struct net_device *netdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key)
|
vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key, u8 *hfunc)
|
||||||
{
|
{
|
||||||
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
|
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
|
||||||
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
|
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
|
||||||
unsigned int n = rssConf->indTableSize;
|
unsigned int n = rssConf->indTableSize;
|
||||||
|
|
||||||
|
if (hfunc)
|
||||||
|
*hfunc = ETH_RSS_HASH_TOP;
|
||||||
|
if (!p)
|
||||||
|
return 0;
|
||||||
while (n--)
|
while (n--)
|
||||||
p[n] = rssConf->indTable[n];
|
p[n] = rssConf->indTable[n];
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -596,13 +600,20 @@ vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key)
|
vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key,
|
||||||
|
const u8 hfunc)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
|
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
|
||||||
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
|
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
|
||||||
|
|
||||||
|
/* We do not allow change in unsupported parameters */
|
||||||
|
if (key ||
|
||||||
|
(hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!p)
|
||||||
|
return 0;
|
||||||
for (i = 0; i < rssConf->indTableSize; i++)
|
for (i = 0; i < rssConf->indTableSize; i++)
|
||||||
rssConf->indTable[i] = p[i];
|
rssConf->indTable[i] = p[i];
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,26 @@ enum ethtool_phys_id_state {
|
||||||
ETHTOOL_ID_OFF
|
ETHTOOL_ID_OFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ETH_RSS_HASH_TOP_BIT, /* Configurable RSS hash function - Toeplitz */
|
||||||
|
ETH_RSS_HASH_XOR_BIT, /* Configurable RSS hash function - Xor */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add your fresh new hash function bits above and remember to update
|
||||||
|
* rss_hash_func_strings[] in ethtool.c
|
||||||
|
*/
|
||||||
|
ETH_RSS_HASH_FUNCS_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
#define __ETH_RSS_HASH_BIT(bit) ((u32)1 << (bit))
|
||||||
|
#define __ETH_RSS_HASH(name) __ETH_RSS_HASH_BIT(ETH_RSS_HASH_##name##_BIT)
|
||||||
|
|
||||||
|
#define ETH_RSS_HASH_TOP __ETH_RSS_HASH(TOP)
|
||||||
|
#define ETH_RSS_HASH_XOR __ETH_RSS_HASH(XOR)
|
||||||
|
|
||||||
|
#define ETH_RSS_HASH_UNKNOWN 0
|
||||||
|
#define ETH_RSS_HASH_NO_CHANGE 0
|
||||||
|
|
||||||
struct net_device;
|
struct net_device;
|
||||||
|
|
||||||
/* Some generic methods drivers may use in their ethtool_ops */
|
/* Some generic methods drivers may use in their ethtool_ops */
|
||||||
|
@ -158,17 +178,14 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
|
||||||
* Returns zero if not supported for this specific device.
|
* Returns zero if not supported for this specific device.
|
||||||
* @get_rxfh_indir_size: Get the size of the RX flow hash indirection table.
|
* @get_rxfh_indir_size: Get the size of the RX flow hash indirection table.
|
||||||
* Returns zero if not supported for this specific device.
|
* Returns zero if not supported for this specific device.
|
||||||
* @get_rxfh: Get the contents of the RX flow hash indirection table and hash
|
* @get_rxfh: Get the contents of the RX flow hash indirection table, hash key
|
||||||
* key.
|
* and/or hash function.
|
||||||
* Will only be called if one or both of @get_rxfh_indir_size and
|
|
||||||
* @get_rxfh_key_size are implemented and return non-zero.
|
|
||||||
* Returns a negative error code or zero.
|
|
||||||
* @set_rxfh: Set the contents of the RX flow hash indirection table and/or
|
|
||||||
* hash key. In case only the indirection table or hash key is to be
|
|
||||||
* changed, the other argument will be %NULL.
|
|
||||||
* Will only be called if one or both of @get_rxfh_indir_size and
|
|
||||||
* @get_rxfh_key_size are implemented and return non-zero.
|
|
||||||
* Returns a negative error code or zero.
|
* Returns a negative error code or zero.
|
||||||
|
* @set_rxfh: Set the contents of the RX flow hash indirection table, hash
|
||||||
|
* key, and/or hash function. Arguments which are set to %NULL or zero
|
||||||
|
* will remain unchanged.
|
||||||
|
* Returns a negative error code or zero. An error code must be returned
|
||||||
|
* if at least one unsupported change was requested.
|
||||||
* @get_channels: Get number of channels.
|
* @get_channels: Get number of channels.
|
||||||
* @set_channels: Set number of channels. Returns a negative error code or
|
* @set_channels: Set number of channels. Returns a negative error code or
|
||||||
* zero.
|
* zero.
|
||||||
|
@ -241,9 +258,10 @@ struct ethtool_ops {
|
||||||
int (*reset)(struct net_device *, u32 *);
|
int (*reset)(struct net_device *, u32 *);
|
||||||
u32 (*get_rxfh_key_size)(struct net_device *);
|
u32 (*get_rxfh_key_size)(struct net_device *);
|
||||||
u32 (*get_rxfh_indir_size)(struct net_device *);
|
u32 (*get_rxfh_indir_size)(struct net_device *);
|
||||||
int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key);
|
int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key,
|
||||||
|
u8 *hfunc);
|
||||||
int (*set_rxfh)(struct net_device *, const u32 *indir,
|
int (*set_rxfh)(struct net_device *, const u32 *indir,
|
||||||
const u8 *key);
|
const u8 *key, const u8 hfunc);
|
||||||
void (*get_channels)(struct net_device *, struct ethtool_channels *);
|
void (*get_channels)(struct net_device *, struct ethtool_channels *);
|
||||||
int (*set_channels)(struct net_device *, struct ethtool_channels *);
|
int (*set_channels)(struct net_device *, struct ethtool_channels *);
|
||||||
int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);
|
int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);
|
||||||
|
|
|
@ -534,6 +534,7 @@ struct ethtool_pauseparam {
|
||||||
* @ETH_SS_NTUPLE_FILTERS: Previously used with %ETHTOOL_GRXNTUPLE;
|
* @ETH_SS_NTUPLE_FILTERS: Previously used with %ETHTOOL_GRXNTUPLE;
|
||||||
* now deprecated
|
* now deprecated
|
||||||
* @ETH_SS_FEATURES: Device feature names
|
* @ETH_SS_FEATURES: Device feature names
|
||||||
|
* @ETH_SS_RSS_HASH_FUNCS: RSS hush function names
|
||||||
*/
|
*/
|
||||||
enum ethtool_stringset {
|
enum ethtool_stringset {
|
||||||
ETH_SS_TEST = 0,
|
ETH_SS_TEST = 0,
|
||||||
|
@ -541,6 +542,7 @@ enum ethtool_stringset {
|
||||||
ETH_SS_PRIV_FLAGS,
|
ETH_SS_PRIV_FLAGS,
|
||||||
ETH_SS_NTUPLE_FILTERS,
|
ETH_SS_NTUPLE_FILTERS,
|
||||||
ETH_SS_FEATURES,
|
ETH_SS_FEATURES,
|
||||||
|
ETH_SS_RSS_HASH_FUNCS,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -884,6 +886,8 @@ struct ethtool_rxfh_indir {
|
||||||
* @key_size: On entry, the array size of the user buffer for the hash key,
|
* @key_size: On entry, the array size of the user buffer for the hash key,
|
||||||
* which may be zero. On return from %ETHTOOL_GRSSH, the size of the
|
* which may be zero. On return from %ETHTOOL_GRSSH, the size of the
|
||||||
* hardware hash key.
|
* hardware hash key.
|
||||||
|
* @hfunc: Defines the current RSS hash function used by HW (or to be set to).
|
||||||
|
* Valid values are one of the %ETH_RSS_HASH_*.
|
||||||
* @rsvd: Reserved for future extensions.
|
* @rsvd: Reserved for future extensions.
|
||||||
* @rss_config: RX ring/queue index for each hash value i.e., indirection table
|
* @rss_config: RX ring/queue index for each hash value i.e., indirection table
|
||||||
* of @indir_size __u32 elements, followed by hash key of @key_size
|
* of @indir_size __u32 elements, followed by hash key of @key_size
|
||||||
|
@ -893,14 +897,16 @@ struct ethtool_rxfh_indir {
|
||||||
* size should be returned. For %ETHTOOL_SRSSH, an @indir_size of
|
* size should be returned. For %ETHTOOL_SRSSH, an @indir_size of
|
||||||
* %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested
|
* %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested
|
||||||
* and a @indir_size of zero means the indir table should be reset to default
|
* and a @indir_size of zero means the indir table should be reset to default
|
||||||
* values.
|
* values. An hfunc of zero means that hash function setting is not requested.
|
||||||
*/
|
*/
|
||||||
struct ethtool_rxfh {
|
struct ethtool_rxfh {
|
||||||
__u32 cmd;
|
__u32 cmd;
|
||||||
__u32 rss_context;
|
__u32 rss_context;
|
||||||
__u32 indir_size;
|
__u32 indir_size;
|
||||||
__u32 key_size;
|
__u32 key_size;
|
||||||
__u32 rsvd[2];
|
__u8 hfunc;
|
||||||
|
__u8 rsvd8[3];
|
||||||
|
__u32 rsvd32;
|
||||||
__u32 rss_config[0];
|
__u32 rss_config[0];
|
||||||
};
|
};
|
||||||
#define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff
|
#define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff
|
||||||
|
|
|
@ -100,6 +100,12 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
|
||||||
[NETIF_F_BUSY_POLL_BIT] = "busy-poll",
|
[NETIF_F_BUSY_POLL_BIT] = "busy-poll",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char
|
||||||
|
rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {
|
||||||
|
[ETH_RSS_HASH_TOP_BIT] = "toeplitz",
|
||||||
|
[ETH_RSS_HASH_XOR_BIT] = "xor",
|
||||||
|
};
|
||||||
|
|
||||||
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
|
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
|
||||||
{
|
{
|
||||||
struct ethtool_gfeatures cmd = {
|
struct ethtool_gfeatures cmd = {
|
||||||
|
@ -185,6 +191,9 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset)
|
||||||
if (sset == ETH_SS_FEATURES)
|
if (sset == ETH_SS_FEATURES)
|
||||||
return ARRAY_SIZE(netdev_features_strings);
|
return ARRAY_SIZE(netdev_features_strings);
|
||||||
|
|
||||||
|
if (sset == ETH_SS_RSS_HASH_FUNCS)
|
||||||
|
return ARRAY_SIZE(rss_hash_func_strings);
|
||||||
|
|
||||||
if (ops->get_sset_count && ops->get_strings)
|
if (ops->get_sset_count && ops->get_strings)
|
||||||
return ops->get_sset_count(dev, sset);
|
return ops->get_sset_count(dev, sset);
|
||||||
else
|
else
|
||||||
|
@ -199,6 +208,9 @@ static void __ethtool_get_strings(struct net_device *dev,
|
||||||
if (stringset == ETH_SS_FEATURES)
|
if (stringset == ETH_SS_FEATURES)
|
||||||
memcpy(data, netdev_features_strings,
|
memcpy(data, netdev_features_strings,
|
||||||
sizeof(netdev_features_strings));
|
sizeof(netdev_features_strings));
|
||||||
|
else if (stringset == ETH_SS_RSS_HASH_FUNCS)
|
||||||
|
memcpy(data, rss_hash_func_strings,
|
||||||
|
sizeof(rss_hash_func_strings));
|
||||||
else
|
else
|
||||||
/* ops->get_strings is valid because checked earlier */
|
/* ops->get_strings is valid because checked earlier */
|
||||||
ops->get_strings(dev, stringset, data);
|
ops->get_strings(dev, stringset, data);
|
||||||
|
@ -618,7 +630,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
|
||||||
if (!indir)
|
if (!indir)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL);
|
ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -679,7 +691,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ops->set_rxfh(dev, indir, NULL);
|
ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(indir);
|
kfree(indir);
|
||||||
|
@ -697,12 +709,11 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
|
||||||
u32 total_size;
|
u32 total_size;
|
||||||
u32 indir_bytes;
|
u32 indir_bytes;
|
||||||
u32 *indir = NULL;
|
u32 *indir = NULL;
|
||||||
|
u8 dev_hfunc = 0;
|
||||||
u8 *hkey = NULL;
|
u8 *hkey = NULL;
|
||||||
u8 *rss_config;
|
u8 *rss_config;
|
||||||
|
|
||||||
if (!(dev->ethtool_ops->get_rxfh_indir_size ||
|
if (!ops->get_rxfh)
|
||||||
dev->ethtool_ops->get_rxfh_key_size) ||
|
|
||||||
!dev->ethtool_ops->get_rxfh)
|
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (ops->get_rxfh_indir_size)
|
if (ops->get_rxfh_indir_size)
|
||||||
|
@ -710,16 +721,14 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
|
||||||
if (ops->get_rxfh_key_size)
|
if (ops->get_rxfh_key_size)
|
||||||
dev_key_size = ops->get_rxfh_key_size(dev);
|
dev_key_size = ops->get_rxfh_key_size(dev);
|
||||||
|
|
||||||
if ((dev_key_size + dev_indir_size) == 0)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
|
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
user_indir_size = rxfh.indir_size;
|
user_indir_size = rxfh.indir_size;
|
||||||
user_key_size = rxfh.key_size;
|
user_key_size = rxfh.key_size;
|
||||||
|
|
||||||
/* Check that reserved fields are 0 for now */
|
/* Check that reserved fields are 0 for now */
|
||||||
if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1])
|
if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
|
||||||
|
rxfh.rsvd8[2] || rxfh.rsvd32)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
rxfh.indir_size = dev_indir_size;
|
rxfh.indir_size = dev_indir_size;
|
||||||
|
@ -727,13 +736,6 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
|
||||||
if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
|
if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
/* If the user buffer size is 0, this is just a query for the
|
|
||||||
* device table size and key size. Otherwise, if the User size is
|
|
||||||
* not equal to device table size or key size it's an error.
|
|
||||||
*/
|
|
||||||
if (!user_indir_size && !user_key_size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
|
if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
|
||||||
(user_key_size && (user_key_size != dev_key_size)))
|
(user_key_size && (user_key_size != dev_key_size)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -750,14 +752,19 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
|
||||||
if (user_key_size)
|
if (user_key_size)
|
||||||
hkey = rss_config + indir_bytes;
|
hkey = rss_config + indir_bytes;
|
||||||
|
|
||||||
ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey);
|
ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
|
||||||
if (!ret) {
|
if (ret)
|
||||||
if (copy_to_user(useraddr +
|
goto out;
|
||||||
offsetof(struct ethtool_rxfh, rss_config[0]),
|
|
||||||
rss_config, total_size))
|
|
||||||
ret = -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, hfunc),
|
||||||
|
&dev_hfunc, sizeof(rxfh.hfunc))) {
|
||||||
|
ret = -EFAULT;
|
||||||
|
} else if (copy_to_user(useraddr +
|
||||||
|
offsetof(struct ethtool_rxfh, rss_config[0]),
|
||||||
|
rss_config, total_size)) {
|
||||||
|
ret = -EFAULT;
|
||||||
|
}
|
||||||
|
out:
|
||||||
kfree(rss_config);
|
kfree(rss_config);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -776,33 +783,31 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
|
||||||
u8 *rss_config;
|
u8 *rss_config;
|
||||||
u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
|
u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
|
||||||
|
|
||||||
if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) ||
|
if (!ops->get_rxnfc || !ops->set_rxfh)
|
||||||
!ops->get_rxnfc || !ops->set_rxfh)
|
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (ops->get_rxfh_indir_size)
|
if (ops->get_rxfh_indir_size)
|
||||||
dev_indir_size = ops->get_rxfh_indir_size(dev);
|
dev_indir_size = ops->get_rxfh_indir_size(dev);
|
||||||
if (ops->get_rxfh_key_size)
|
if (ops->get_rxfh_key_size)
|
||||||
dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev);
|
dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev);
|
||||||
if ((dev_key_size + dev_indir_size) == 0)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
|
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
/* Check that reserved fields are 0 for now */
|
/* Check that reserved fields are 0 for now */
|
||||||
if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1])
|
if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
|
||||||
|
rxfh.rsvd8[2] || rxfh.rsvd32)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* If either indir or hash key is valid, proceed further.
|
/* If either indir, hash key or function is valid, proceed further.
|
||||||
* It is not valid to request that both be unchanged.
|
* Must request at least one change: indir size, hash key or function.
|
||||||
*/
|
*/
|
||||||
if ((rxfh.indir_size &&
|
if ((rxfh.indir_size &&
|
||||||
rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
|
rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
|
||||||
rxfh.indir_size != dev_indir_size) ||
|
rxfh.indir_size != dev_indir_size) ||
|
||||||
(rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
|
(rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
|
||||||
(rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
|
(rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
|
||||||
rxfh.key_size == 0))
|
rxfh.key_size == 0 && rxfh.hfunc == ETH_RSS_HASH_NO_CHANGE))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
|
if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
|
||||||
|
@ -845,7 +850,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ops->set_rxfh(dev, indir, hkey);
|
ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(rss_config);
|
kfree(rss_config);
|
||||||
|
|
Loading…
Reference in New Issue