aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorEyal Perry <eyalpe@mellanox.com>2014-12-02 11:12:10 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-08 21:07:10 -0500
commit892311f66f2411b813ca631009356891a0c2b0a1 (patch)
tree42267098964290cf349abd6733267c24867f2318 /net/core
parent18b5427ae1654803930b97590ac5a85245861646 (diff)
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>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/ethtool.c69
1 files changed, 37 insertions, 32 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 715f51f321e9..550892cd6b3f 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -100,6 +100,12 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
100 [NETIF_F_BUSY_POLL_BIT] = "busy-poll", 100 [NETIF_F_BUSY_POLL_BIT] = "busy-poll",
101}; 101};
102 102
103static const char
104rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {
105 [ETH_RSS_HASH_TOP_BIT] = "toeplitz",
106 [ETH_RSS_HASH_XOR_BIT] = "xor",
107};
108
103static int ethtool_get_features(struct net_device *dev, void __user *useraddr) 109static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
104{ 110{
105 struct ethtool_gfeatures cmd = { 111 struct ethtool_gfeatures cmd = {
@@ -185,6 +191,9 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset)
185 if (sset == ETH_SS_FEATURES) 191 if (sset == ETH_SS_FEATURES)
186 return ARRAY_SIZE(netdev_features_strings); 192 return ARRAY_SIZE(netdev_features_strings);
187 193
194 if (sset == ETH_SS_RSS_HASH_FUNCS)
195 return ARRAY_SIZE(rss_hash_func_strings);
196
188 if (ops->get_sset_count && ops->get_strings) 197 if (ops->get_sset_count && ops->get_strings)
189 return ops->get_sset_count(dev, sset); 198 return ops->get_sset_count(dev, sset);
190 else 199 else
@@ -199,6 +208,9 @@ static void __ethtool_get_strings(struct net_device *dev,
199 if (stringset == ETH_SS_FEATURES) 208 if (stringset == ETH_SS_FEATURES)
200 memcpy(data, netdev_features_strings, 209 memcpy(data, netdev_features_strings,
201 sizeof(netdev_features_strings)); 210 sizeof(netdev_features_strings));
211 else if (stringset == ETH_SS_RSS_HASH_FUNCS)
212 memcpy(data, rss_hash_func_strings,
213 sizeof(rss_hash_func_strings));
202 else 214 else
203 /* ops->get_strings is valid because checked earlier */ 215 /* ops->get_strings is valid because checked earlier */
204 ops->get_strings(dev, stringset, data); 216 ops->get_strings(dev, stringset, data);
@@ -618,7 +630,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
618 if (!indir) 630 if (!indir)
619 return -ENOMEM; 631 return -ENOMEM;
620 632
621 ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL); 633 ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
622 if (ret) 634 if (ret)
623 goto out; 635 goto out;
624 636
@@ -679,7 +691,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
679 goto out; 691 goto out;
680 } 692 }
681 693
682 ret = ops->set_rxfh(dev, indir, NULL); 694 ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE);
683 695
684out: 696out:
685 kfree(indir); 697 kfree(indir);
@@ -697,12 +709,11 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
697 u32 total_size; 709 u32 total_size;
698 u32 indir_bytes; 710 u32 indir_bytes;
699 u32 *indir = NULL; 711 u32 *indir = NULL;
712 u8 dev_hfunc = 0;
700 u8 *hkey = NULL; 713 u8 *hkey = NULL;
701 u8 *rss_config; 714 u8 *rss_config;
702 715
703 if (!(dev->ethtool_ops->get_rxfh_indir_size || 716 if (!ops->get_rxfh)
704 dev->ethtool_ops->get_rxfh_key_size) ||
705 !dev->ethtool_ops->get_rxfh)
706 return -EOPNOTSUPP; 717 return -EOPNOTSUPP;
707 718
708 if (ops->get_rxfh_indir_size) 719 if (ops->get_rxfh_indir_size)
@@ -710,16 +721,14 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
710 if (ops->get_rxfh_key_size) 721 if (ops->get_rxfh_key_size)
711 dev_key_size = ops->get_rxfh_key_size(dev); 722 dev_key_size = ops->get_rxfh_key_size(dev);
712 723
713 if ((dev_key_size + dev_indir_size) == 0)
714 return -EOPNOTSUPP;
715
716 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) 724 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
717 return -EFAULT; 725 return -EFAULT;
718 user_indir_size = rxfh.indir_size; 726 user_indir_size = rxfh.indir_size;
719 user_key_size = rxfh.key_size; 727 user_key_size = rxfh.key_size;
720 728
721 /* Check that reserved fields are 0 for now */ 729 /* Check that reserved fields are 0 for now */
722 if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) 730 if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
731 rxfh.rsvd8[2] || rxfh.rsvd32)
723 return -EINVAL; 732 return -EINVAL;
724 733
725 rxfh.indir_size = dev_indir_size; 734 rxfh.indir_size = dev_indir_size;
@@ -727,13 +736,6 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
727 if (copy_to_user(useraddr, &rxfh, sizeof(rxfh))) 736 if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
728 return -EFAULT; 737 return -EFAULT;
729 738
730 /* If the user buffer size is 0, this is just a query for the
731 * device table size and key size. Otherwise, if the User size is
732 * not equal to device table size or key size it's an error.
733 */
734 if (!user_indir_size && !user_key_size)
735 return 0;
736
737 if ((user_indir_size && (user_indir_size != dev_indir_size)) || 739 if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
738 (user_key_size && (user_key_size != dev_key_size))) 740 (user_key_size && (user_key_size != dev_key_size)))
739 return -EINVAL; 741 return -EINVAL;
@@ -750,14 +752,19 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
750 if (user_key_size) 752 if (user_key_size)
751 hkey = rss_config + indir_bytes; 753 hkey = rss_config + indir_bytes;
752 754
753 ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey); 755 ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
754 if (!ret) { 756 if (ret)
755 if (copy_to_user(useraddr + 757 goto out;
756 offsetof(struct ethtool_rxfh, rss_config[0]),
757 rss_config, total_size))
758 ret = -EFAULT;
759 }
760 758
759 if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, hfunc),
760 &dev_hfunc, sizeof(rxfh.hfunc))) {
761 ret = -EFAULT;
762 } else if (copy_to_user(useraddr +
763 offsetof(struct ethtool_rxfh, rss_config[0]),
764 rss_config, total_size)) {
765 ret = -EFAULT;
766 }
767out:
761 kfree(rss_config); 768 kfree(rss_config);
762 769
763 return ret; 770 return ret;
@@ -776,33 +783,31 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
776 u8 *rss_config; 783 u8 *rss_config;
777 u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); 784 u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
778 785
779 if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || 786 if (!ops->get_rxnfc || !ops->set_rxfh)
780 !ops->get_rxnfc || !ops->set_rxfh)
781 return -EOPNOTSUPP; 787 return -EOPNOTSUPP;
782 788
783 if (ops->get_rxfh_indir_size) 789 if (ops->get_rxfh_indir_size)
784 dev_indir_size = ops->get_rxfh_indir_size(dev); 790 dev_indir_size = ops->get_rxfh_indir_size(dev);
785 if (ops->get_rxfh_key_size) 791 if (ops->get_rxfh_key_size)
786 dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); 792 dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev);
787 if ((dev_key_size + dev_indir_size) == 0)
788 return -EOPNOTSUPP;
789 793
790 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) 794 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
791 return -EFAULT; 795 return -EFAULT;
792 796
793 /* Check that reserved fields are 0 for now */ 797 /* Check that reserved fields are 0 for now */
794 if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) 798 if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
799 rxfh.rsvd8[2] || rxfh.rsvd32)
795 return -EINVAL; 800 return -EINVAL;
796 801
797 /* If either indir or hash key is valid, proceed further. 802 /* If either indir, hash key or function is valid, proceed further.
798 * It is not valid to request that both be unchanged. 803 * Must request at least one change: indir size, hash key or function.
799 */ 804 */
800 if ((rxfh.indir_size && 805 if ((rxfh.indir_size &&
801 rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE && 806 rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
802 rxfh.indir_size != dev_indir_size) || 807 rxfh.indir_size != dev_indir_size) ||
803 (rxfh.key_size && (rxfh.key_size != dev_key_size)) || 808 (rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
804 (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE && 809 (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
805 rxfh.key_size == 0)) 810 rxfh.key_size == 0 && rxfh.hfunc == ETH_RSS_HASH_NO_CHANGE))
806 return -EINVAL; 811 return -EINVAL;
807 812
808 if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) 813 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,
845 } 850 }
846 } 851 }
847 852
848 ret = ops->set_rxfh(dev, indir, hkey); 853 ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
849 854
850out: 855out:
851 kfree(rss_config); 856 kfree(rss_config);