diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2011-12-16 08:33:23 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-19 15:50:52 -0500 |
commit | 90415477bf1356f72acc34063ff52441fc10a754 (patch) | |
tree | 5ea23ba1f29037701129d7653475f7d984fe6bcd /drivers/net/ethernet/broadcom | |
parent | c2c20ef43d00b1439631e603f8dcee9a803cd8b3 (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')
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 108 |
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 | ||
8223 | void tg3_rss_init_indir_tbl(struct tg3 *tp) | 8223 | static 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 | |||
8232 | static 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 | ||
8237 | void tg3_rss_write_indir_tbl(struct tg3 *tp) | 8254 | static 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 | ||
10739 | static 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 | |||
10768 | static 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 | |||
10779 | static 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 | |||
10790 | static 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 | |||
10722 | static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf) | 10811 | static 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 | ||
11954 | static void __devinit tg3_get_eeprom_size(struct tg3 *tp) | 12047 | static 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 | ||