tg3: Make the RSS indir tbl admin configurable
This patch adds the ethtool callbacks necessary to change the rss indirection table from userspace. Should the number of interrupts change (e.g. across a close / open call, or through a reset) and any one of the indirection table values fall out-of-range, the driver will reset the indirection table to a default layout. [Integrated many suggestions made by Ben Hutchings.] Changes since v3 * Removed TG3_FLAG_SUPPORT_MSIX checks at the start of tg3_get_rxfh_indir() and tg3_set_rxfh_indir(). Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c2c20ef43d
commit
90415477bf
@ -8220,21 +8220,38 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
|
||||
tw32(JMB_REPLENISH_LWM, bdcache_maxcnt);
|
||||
}
|
||||
|
||||
void tg3_rss_init_indir_tbl(struct tg3 *tp)
|
||||
static void tg3_rss_init_dflt_indir_tbl(struct tg3 *tp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
|
||||
tp->rss_ind_tbl[i] =
|
||||
ethtool_rxfh_indir_default(i, tp->irq_cnt - 1);
|
||||
}
|
||||
|
||||
static void tg3_rss_check_indir_tbl(struct tg3 *tp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!tg3_flag(tp, SUPPORT_MSIX))
|
||||
return;
|
||||
|
||||
if (tp->irq_cnt <= 2)
|
||||
if (tp->irq_cnt <= 2) {
|
||||
memset(&tp->rss_ind_tbl[0], 0, sizeof(tp->rss_ind_tbl));
|
||||
else
|
||||
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
|
||||
tp->rss_ind_tbl[i] = i % (tp->irq_cnt - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Validate table against current IRQ count */
|
||||
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++) {
|
||||
if (tp->rss_ind_tbl[i] >= tp->irq_cnt - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != TG3_RSS_INDIR_TBL_SIZE)
|
||||
tg3_rss_init_dflt_indir_tbl(tp);
|
||||
}
|
||||
|
||||
void tg3_rss_write_indir_tbl(struct tg3 *tp)
|
||||
static void tg3_rss_write_indir_tbl(struct tg3 *tp)
|
||||
{
|
||||
int i = 0;
|
||||
u32 reg = MAC_RSS_INDIR_TBL_0;
|
||||
@ -9668,7 +9685,7 @@ static int tg3_open(struct net_device *dev)
|
||||
*/
|
||||
tg3_ints_init(tp);
|
||||
|
||||
tg3_rss_init_indir_tbl(tp);
|
||||
tg3_rss_check_indir_tbl(tp);
|
||||
|
||||
/* The placement of this call is tied
|
||||
* to the setup and use of Host TX descriptors.
|
||||
@ -10719,6 +10736,78 @@ static int tg3_get_sset_count(struct net_device *dev, int sset)
|
||||
}
|
||||
}
|
||||
|
||||
static int tg3_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
|
||||
u32 *rules __always_unused)
|
||||
{
|
||||
struct tg3 *tp = netdev_priv(dev);
|
||||
|
||||
if (!tg3_flag(tp, SUPPORT_MSIX))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (info->cmd) {
|
||||
case ETHTOOL_GRXRINGS:
|
||||
if (netif_running(tp->dev))
|
||||
info->data = tp->irq_cnt;
|
||||
else {
|
||||
info->data = num_online_cpus();
|
||||
if (info->data > TG3_IRQ_MAX_VECS_RSS)
|
||||
info->data = TG3_IRQ_MAX_VECS_RSS;
|
||||
}
|
||||
|
||||
/* The first interrupt vector only
|
||||
* handles link interrupts.
|
||||
*/
|
||||
info->data -= 1;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 tg3_get_rxfh_indir_size(struct net_device *dev)
|
||||
{
|
||||
u32 size = 0;
|
||||
struct tg3 *tp = netdev_priv(dev);
|
||||
|
||||
if (tg3_flag(tp, SUPPORT_MSIX))
|
||||
size = TG3_RSS_INDIR_TBL_SIZE;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir)
|
||||
{
|
||||
struct tg3 *tp = netdev_priv(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
|
||||
indir[i] = tp->rss_ind_tbl[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tg3_set_rxfh_indir(struct net_device *dev, const u32 *indir)
|
||||
{
|
||||
struct tg3 *tp = netdev_priv(dev);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
|
||||
tp->rss_ind_tbl[i] = indir[i];
|
||||
|
||||
if (!netif_running(dev) || !tg3_flag(tp, ENABLE_RSS))
|
||||
return 0;
|
||||
|
||||
/* It is legal to write the indirection
|
||||
* table while the device is running.
|
||||
*/
|
||||
tg3_full_lock(tp, 0);
|
||||
tg3_rss_write_indir_tbl(tp);
|
||||
tg3_full_unlock(tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
|
||||
{
|
||||
switch (stringset) {
|
||||
@ -11949,6 +12038,10 @@ static const struct ethtool_ops tg3_ethtool_ops = {
|
||||
.get_coalesce = tg3_get_coalesce,
|
||||
.set_coalesce = tg3_set_coalesce,
|
||||
.get_sset_count = tg3_get_sset_count,
|
||||
.get_rxnfc = tg3_get_rxnfc,
|
||||
.get_rxfh_indir_size = tg3_get_rxfh_indir_size,
|
||||
.get_rxfh_indir = tg3_get_rxfh_indir,
|
||||
.set_rxfh_indir = tg3_set_rxfh_indir,
|
||||
};
|
||||
|
||||
static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
|
||||
@ -14051,6 +14144,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
|
||||
if (tg3_flag(tp, 57765_PLUS)) {
|
||||
tg3_flag_set(tp, SUPPORT_MSIX);
|
||||
tp->irq_max = TG3_IRQ_MAX_VECS;
|
||||
tg3_rss_init_dflt_indir_tbl(tp);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user