Skip to content

Commit

Permalink
tg3: Make the RSS indir tbl admin configurable
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matt Carlson authored and David S. Miller committed Dec 19, 2011
1 parent c2c20ef commit 9041547
Showing 1 changed file with 101 additions and 7 deletions.
108 changes: 101 additions & 7 deletions drivers/net/ethernet/broadcom/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
}

Expand Down

0 comments on commit 9041547

Please sign in to comment.