aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/broadcom/tg3.c
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2011-12-16 08:33:23 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-19 15:50:52 -0500
commit90415477bf1356f72acc34063ff52441fc10a754 (patch)
tree5ea23ba1f29037701129d7653475f7d984fe6bcd /drivers/net/ethernet/broadcom/tg3.c
parentc2c20ef43d00b1439631e603f8dcee9a803cd8b3 (diff)
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>
Diffstat (limited to 'drivers/net/ethernet/broadcom/tg3.c')
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c108
1 files changed, 101 insertions, 7 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 8bf11ca30efe..00213968d210 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -8220,21 +8220,38 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
8220 tw32(JMB_REPLENISH_LWM, bdcache_maxcnt); 8220 tw32(JMB_REPLENISH_LWM, bdcache_maxcnt);
8221} 8221}
8222 8222
8223void tg3_rss_init_indir_tbl(struct tg3 *tp) 8223static void tg3_rss_init_dflt_indir_tbl(struct tg3 *tp)
8224{
8225 int i;
8226
8227 for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
8228 tp->rss_ind_tbl[i] =
8229 ethtool_rxfh_indir_default(i, tp->irq_cnt - 1);
8230}
8231
8232static void tg3_rss_check_indir_tbl(struct tg3 *tp)
8224{ 8233{
8225 int i; 8234 int i;
8226 8235
8227 if (!tg3_flag(tp, SUPPORT_MSIX)) 8236 if (!tg3_flag(tp, SUPPORT_MSIX))
8228 return; 8237 return;
8229 8238
8230 if (tp->irq_cnt <= 2) 8239 if (tp->irq_cnt <= 2) {
8231 memset(&tp->rss_ind_tbl[0], 0, sizeof(tp->rss_ind_tbl)); 8240 memset(&tp->rss_ind_tbl[0], 0, sizeof(tp->rss_ind_tbl));
8232 else 8241 return;
8233 for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++) 8242 }
8234 tp->rss_ind_tbl[i] = i % (tp->irq_cnt - 1); 8243
8244 /* Validate table against current IRQ count */
8245 for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++) {
8246 if (tp->rss_ind_tbl[i] >= tp->irq_cnt - 1)
8247 break;
8248 }
8249
8250 if (i != TG3_RSS_INDIR_TBL_SIZE)
8251 tg3_rss_init_dflt_indir_tbl(tp);
8235} 8252}
8236 8253
8237void tg3_rss_write_indir_tbl(struct tg3 *tp) 8254static void tg3_rss_write_indir_tbl(struct tg3 *tp)
8238{ 8255{
8239 int i = 0; 8256 int i = 0;
8240 u32 reg = MAC_RSS_INDIR_TBL_0; 8257 u32 reg = MAC_RSS_INDIR_TBL_0;
@@ -9668,7 +9685,7 @@ static int tg3_open(struct net_device *dev)
9668 */ 9685 */
9669 tg3_ints_init(tp); 9686 tg3_ints_init(tp);
9670 9687
9671 tg3_rss_init_indir_tbl(tp); 9688 tg3_rss_check_indir_tbl(tp);
9672 9689
9673 /* The placement of this call is tied 9690 /* The placement of this call is tied
9674 * to the setup and use of Host TX descriptors. 9691 * 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)
10719 } 10736 }
10720} 10737}
10721 10738
10739static int tg3_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
10740 u32 *rules __always_unused)
10741{
10742 struct tg3 *tp = netdev_priv(dev);
10743
10744 if (!tg3_flag(tp, SUPPORT_MSIX))
10745 return -EOPNOTSUPP;
10746
10747 switch (info->cmd) {
10748 case ETHTOOL_GRXRINGS:
10749 if (netif_running(tp->dev))
10750 info->data = tp->irq_cnt;
10751 else {
10752 info->data = num_online_cpus();
10753 if (info->data > TG3_IRQ_MAX_VECS_RSS)
10754 info->data = TG3_IRQ_MAX_VECS_RSS;
10755 }
10756
10757 /* The first interrupt vector only
10758 * handles link interrupts.
10759 */
10760 info->data -= 1;
10761 return 0;
10762
10763 default:
10764 return -EOPNOTSUPP;
10765 }
10766}
10767
10768static u32 tg3_get_rxfh_indir_size(struct net_device *dev)
10769{
10770 u32 size = 0;
10771 struct tg3 *tp = netdev_priv(dev);
10772
10773 if (tg3_flag(tp, SUPPORT_MSIX))
10774 size = TG3_RSS_INDIR_TBL_SIZE;
10775
10776 return size;
10777}
10778
10779static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir)
10780{
10781 struct tg3 *tp = netdev_priv(dev);
10782 int i;
10783
10784 for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
10785 indir[i] = tp->rss_ind_tbl[i];
10786
10787 return 0;
10788}
10789
10790static int tg3_set_rxfh_indir(struct net_device *dev, const u32 *indir)
10791{
10792 struct tg3 *tp = netdev_priv(dev);
10793 size_t i;
10794
10795 for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
10796 tp->rss_ind_tbl[i] = indir[i];
10797
10798 if (!netif_running(dev) || !tg3_flag(tp, ENABLE_RSS))
10799 return 0;
10800
10801 /* It is legal to write the indirection
10802 * table while the device is running.
10803 */
10804 tg3_full_lock(tp, 0);
10805 tg3_rss_write_indir_tbl(tp);
10806 tg3_full_unlock(tp);
10807
10808 return 0;
10809}
10810
10722static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 10811static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
10723{ 10812{
10724 switch (stringset) { 10813 switch (stringset) {
@@ -11949,6 +12038,10 @@ static const struct ethtool_ops tg3_ethtool_ops = {
11949 .get_coalesce = tg3_get_coalesce, 12038 .get_coalesce = tg3_get_coalesce,
11950 .set_coalesce = tg3_set_coalesce, 12039 .set_coalesce = tg3_set_coalesce,
11951 .get_sset_count = tg3_get_sset_count, 12040 .get_sset_count = tg3_get_sset_count,
12041 .get_rxnfc = tg3_get_rxnfc,
12042 .get_rxfh_indir_size = tg3_get_rxfh_indir_size,
12043 .get_rxfh_indir = tg3_get_rxfh_indir,
12044 .set_rxfh_indir = tg3_set_rxfh_indir,
11952}; 12045};
11953 12046
11954static void __devinit tg3_get_eeprom_size(struct tg3 *tp) 12047static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -14051,6 +14144,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
14051 if (tg3_flag(tp, 57765_PLUS)) { 14144 if (tg3_flag(tp, 57765_PLUS)) {
14052 tg3_flag_set(tp, SUPPORT_MSIX); 14145 tg3_flag_set(tp, SUPPORT_MSIX);
14053 tp->irq_max = TG3_IRQ_MAX_VECS; 14146 tp->irq_max = TG3_IRQ_MAX_VECS;
14147 tg3_rss_init_dflt_indir_tbl(tp);
14054 } 14148 }
14055 } 14149 }
14056 14150