diff options
author | David S. Miller <davem@davemloft.net> | 2014-06-03 02:07:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-03 02:07:02 -0400 |
commit | 014b20133bcd442db554c2d2d86181b34cd15b66 (patch) | |
tree | 3402034d4bba5628d21c98258634c58d5bb46bb7 | |
parent | a68ab98e6c7ab0955babcdc45ca446886f3bfb25 (diff) | |
parent | f062a3844845d267e3716cbc188ad502a15898b7 (diff) |
Merge branch 'ethtool-rssh-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/net-next
Ben Hutchings says:
====================
Pull request: Fixes for new ethtool RSS commands
This addresses several problems I previously identified with the new
ETHTOOL_{G,S}RSSH commands:
1. Missing validation of reserved parameters
2. Vague documentation
3. Use of unnamed magic number
4. No consolidation with existing driver operations
I don't currently have access to suitable network hardware, but have
tested these changes with a dummy driver that can support various
combinations of operations and sizes, together with (a) Debian's ethtool
3.13 (b) ethtool 3.14 with the submitted patch to use ETHTOOL_{G,S}RSSH
and minor adjustment for fixes 1 and 3.
v2: Update RSS operations in vmxnet3 too
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 15 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_ethtool.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 15 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ethtool.c | 10 | ||||
-rw-r--r-- | drivers/net/vmxnet3/vmxnet3_ethtool.c | 8 | ||||
-rw-r--r-- | include/linux/ethtool.h | 24 | ||||
-rw-r--r-- | include/uapi/linux/ethtool.h | 25 | ||||
-rw-r--r-- | net/core/ethtool.c | 110 |
14 files changed, 120 insertions, 129 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 5203a8924edf..bd0600cf7266 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | |||
@@ -3316,7 +3316,7 @@ static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev) | |||
3316 | return T_ETH_INDIRECTION_TABLE_SIZE; | 3316 | return T_ETH_INDIRECTION_TABLE_SIZE; |
3317 | } | 3317 | } |
3318 | 3318 | ||
3319 | static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) | 3319 | static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key) |
3320 | { | 3320 | { |
3321 | struct bnx2x *bp = netdev_priv(dev); | 3321 | struct bnx2x *bp = netdev_priv(dev); |
3322 | u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; | 3322 | u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; |
@@ -3340,14 +3340,15 @@ static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) | |||
3340 | return 0; | 3340 | return 0; |
3341 | } | 3341 | } |
3342 | 3342 | ||
3343 | static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir) | 3343 | static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir, |
3344 | const u8 *key) | ||
3344 | { | 3345 | { |
3345 | struct bnx2x *bp = netdev_priv(dev); | 3346 | struct bnx2x *bp = netdev_priv(dev); |
3346 | size_t i; | 3347 | size_t i; |
3347 | 3348 | ||
3348 | for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { | 3349 | for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { |
3349 | /* | 3350 | /* |
3350 | * The same as in bnx2x_get_rxfh_indir: we can't use a memcpy() | 3351 | * The same as in bnx2x_get_rxfh: we can't use a memcpy() |
3351 | * as an internal storage of an indirection table is a u8 array | 3352 | * as an internal storage of an indirection table is a u8 array |
3352 | * while indir->ring_index points to an array of u32. | 3353 | * while indir->ring_index points to an array of u32. |
3353 | * | 3354 | * |
@@ -3471,8 +3472,8 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { | |||
3471 | .get_rxnfc = bnx2x_get_rxnfc, | 3472 | .get_rxnfc = bnx2x_get_rxnfc, |
3472 | .set_rxnfc = bnx2x_set_rxnfc, | 3473 | .set_rxnfc = bnx2x_set_rxnfc, |
3473 | .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, | 3474 | .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, |
3474 | .get_rxfh_indir = bnx2x_get_rxfh_indir, | 3475 | .get_rxfh = bnx2x_get_rxfh, |
3475 | .set_rxfh_indir = bnx2x_set_rxfh_indir, | 3476 | .set_rxfh = bnx2x_set_rxfh, |
3476 | .get_channels = bnx2x_get_channels, | 3477 | .get_channels = bnx2x_get_channels, |
3477 | .set_channels = bnx2x_set_channels, | 3478 | .set_channels = bnx2x_set_channels, |
3478 | .get_module_info = bnx2x_get_module_info, | 3479 | .get_module_info = bnx2x_get_module_info, |
@@ -3498,8 +3499,8 @@ static const struct ethtool_ops bnx2x_vf_ethtool_ops = { | |||
3498 | .get_rxnfc = bnx2x_get_rxnfc, | 3499 | .get_rxnfc = bnx2x_get_rxnfc, |
3499 | .set_rxnfc = bnx2x_set_rxnfc, | 3500 | .set_rxnfc = bnx2x_set_rxnfc, |
3500 | .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, | 3501 | .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, |
3501 | .get_rxfh_indir = bnx2x_get_rxfh_indir, | 3502 | .get_rxfh = bnx2x_get_rxfh, |
3502 | .set_rxfh_indir = bnx2x_set_rxfh_indir, | 3503 | .set_rxfh = bnx2x_set_rxfh, |
3503 | .get_channels = bnx2x_get_channels, | 3504 | .get_channels = bnx2x_get_channels, |
3504 | .set_channels = bnx2x_set_channels, | 3505 | .set_channels = bnx2x_set_channels, |
3505 | }; | 3506 | }; |
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 3b74da5f48a1..df2792d8383d 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c | |||
@@ -12532,7 +12532,7 @@ static u32 tg3_get_rxfh_indir_size(struct net_device *dev) | |||
12532 | return size; | 12532 | return size; |
12533 | } | 12533 | } |
12534 | 12534 | ||
12535 | static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir) | 12535 | static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key) |
12536 | { | 12536 | { |
12537 | struct tg3 *tp = netdev_priv(dev); | 12537 | struct tg3 *tp = netdev_priv(dev); |
12538 | int i; | 12538 | int i; |
@@ -12543,7 +12543,7 @@ static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir) | |||
12543 | return 0; | 12543 | return 0; |
12544 | } | 12544 | } |
12545 | 12545 | ||
12546 | static int tg3_set_rxfh_indir(struct net_device *dev, const u32 *indir) | 12546 | static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key) |
12547 | { | 12547 | { |
12548 | struct tg3 *tp = netdev_priv(dev); | 12548 | struct tg3 *tp = netdev_priv(dev); |
12549 | size_t i; | 12549 | size_t i; |
@@ -14075,8 +14075,8 @@ static const struct ethtool_ops tg3_ethtool_ops = { | |||
14075 | .get_sset_count = tg3_get_sset_count, | 14075 | .get_sset_count = tg3_get_sset_count, |
14076 | .get_rxnfc = tg3_get_rxnfc, | 14076 | .get_rxnfc = tg3_get_rxnfc, |
14077 | .get_rxfh_indir_size = tg3_get_rxfh_indir_size, | 14077 | .get_rxfh_indir_size = tg3_get_rxfh_indir_size, |
14078 | .get_rxfh_indir = tg3_get_rxfh_indir, | 14078 | .get_rxfh = tg3_get_rxfh, |
14079 | .set_rxfh_indir = tg3_set_rxfh_indir, | 14079 | .set_rxfh = tg3_set_rxfh, |
14080 | .get_channels = tg3_get_channels, | 14080 | .get_channels = tg3_get_channels, |
14081 | .set_channels = tg3_set_channels, | 14081 | .set_channels = tg3_set_channels, |
14082 | .get_ts_info = tg3_get_ts_info, | 14082 | .get_ts_info = tg3_get_ts_info, |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 266a5bc6aedf..8cf6be93f491 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
@@ -2739,7 +2739,7 @@ static u32 get_rss_table_size(struct net_device *dev) | |||
2739 | return pi->rss_size; | 2739 | return pi->rss_size; |
2740 | } | 2740 | } |
2741 | 2741 | ||
2742 | static int get_rss_table(struct net_device *dev, u32 *p) | 2742 | static int get_rss_table(struct net_device *dev, u32 *p, u8 *key) |
2743 | { | 2743 | { |
2744 | const struct port_info *pi = netdev_priv(dev); | 2744 | const struct port_info *pi = netdev_priv(dev); |
2745 | unsigned int n = pi->rss_size; | 2745 | unsigned int n = pi->rss_size; |
@@ -2749,7 +2749,7 @@ static int get_rss_table(struct net_device *dev, u32 *p) | |||
2749 | return 0; | 2749 | return 0; |
2750 | } | 2750 | } |
2751 | 2751 | ||
2752 | static int set_rss_table(struct net_device *dev, const u32 *p) | 2752 | static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key) |
2753 | { | 2753 | { |
2754 | unsigned int i; | 2754 | unsigned int i; |
2755 | struct port_info *pi = netdev_priv(dev); | 2755 | struct port_info *pi = netdev_priv(dev); |
@@ -2851,8 +2851,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = { | |||
2851 | .set_wol = set_wol, | 2851 | .set_wol = set_wol, |
2852 | .get_rxnfc = get_rxnfc, | 2852 | .get_rxnfc = get_rxnfc, |
2853 | .get_rxfh_indir_size = get_rss_table_size, | 2853 | .get_rxfh_indir_size = get_rss_table_size, |
2854 | .get_rxfh_indir = get_rss_table, | 2854 | .get_rxfh = get_rss_table, |
2855 | .set_rxfh_indir = set_rss_table, | 2855 | .set_rxfh = set_rss_table, |
2856 | .flash_device = set_flash, | 2856 | .flash_device = set_flash, |
2857 | }; | 2857 | }; |
2858 | 2858 | ||
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index a568f7d1a24c..f4ea3490f446 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c | |||
@@ -2065,7 +2065,7 @@ int be_cmd_reset_function(struct be_adapter *adapter) | |||
2065 | } | 2065 | } |
2066 | 2066 | ||
2067 | int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, | 2067 | int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, |
2068 | u32 rss_hash_opts, u16 table_size, u8 *rss_hkey) | 2068 | u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey) |
2069 | { | 2069 | { |
2070 | struct be_mcc_wrb *wrb; | 2070 | struct be_mcc_wrb *wrb; |
2071 | struct be_cmd_req_rss_config *req; | 2071 | struct be_cmd_req_rss_config *req; |
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index d4616ffb7238..3e0a6b243806 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h | |||
@@ -2082,7 +2082,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, | |||
2082 | u32 *function_mode, u32 *function_caps, u16 *asic_rev); | 2082 | u32 *function_mode, u32 *function_caps, u16 *asic_rev); |
2083 | int be_cmd_reset_function(struct be_adapter *adapter); | 2083 | int be_cmd_reset_function(struct be_adapter *adapter); |
2084 | int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, | 2084 | int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, |
2085 | u32 rss_hash_opts, u16 table_size, u8 *rss_hkey); | 2085 | u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey); |
2086 | int be_process_mcc(struct be_adapter *adapter); | 2086 | int be_process_mcc(struct be_adapter *adapter); |
2087 | int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon, | 2087 | int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon, |
2088 | u8 status, u8 state); | 2088 | u8 status, u8 state); |
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 970ae337daac..e2da4d20dd3d 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c | |||
@@ -1117,7 +1117,8 @@ static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) | |||
1117 | return 0; | 1117 | return 0; |
1118 | } | 1118 | } |
1119 | 1119 | ||
1120 | static int be_set_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) | 1120 | static int be_set_rxfh(struct net_device *netdev, const u32 *indir, |
1121 | const u8 *hkey) | ||
1121 | { | 1122 | { |
1122 | int rc = 0, i, j; | 1123 | int rc = 0, i, j; |
1123 | struct be_adapter *adapter = netdev_priv(netdev); | 1124 | struct be_adapter *adapter = netdev_priv(netdev); |
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index df4dcfd364d8..9cd381a6c4be 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | |||
@@ -624,13 +624,14 @@ static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev) | |||
624 | } | 624 | } |
625 | 625 | ||
626 | /** | 626 | /** |
627 | * i40evf_get_rxfh_indir - get the rx flow hash indirection table | 627 | * i40evf_get_rxfh - get the rx flow hash indirection table |
628 | * @netdev: network interface device structure | 628 | * @netdev: network interface device structure |
629 | * @indir: indirection table | 629 | * @indir: indirection table |
630 | * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) | ||
630 | * | 631 | * |
631 | * Reads the indirection table directly from the hardware. Always returns 0. | 632 | * Reads the indirection table directly from the hardware. Always returns 0. |
632 | **/ | 633 | **/ |
633 | static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir) | 634 | static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) |
634 | { | 635 | { |
635 | struct i40evf_adapter *adapter = netdev_priv(netdev); | 636 | struct i40evf_adapter *adapter = netdev_priv(netdev); |
636 | struct i40e_hw *hw = &adapter->hw; | 637 | struct i40e_hw *hw = &adapter->hw; |
@@ -648,14 +649,16 @@ static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir) | |||
648 | } | 649 | } |
649 | 650 | ||
650 | /** | 651 | /** |
651 | * i40evf_set_rxfh_indir - set the rx flow hash indirection table | 652 | * i40evf_set_rxfh - set the rx flow hash indirection table |
652 | * @netdev: network interface device structure | 653 | * @netdev: network interface device structure |
653 | * @indir: indirection table | 654 | * @indir: indirection table |
655 | * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) | ||
654 | * | 656 | * |
655 | * Returns -EINVAL if the table specifies an inavlid queue id, otherwise | 657 | * Returns -EINVAL if the table specifies an inavlid queue id, otherwise |
656 | * returns 0 after programming the table. | 658 | * returns 0 after programming the table. |
657 | **/ | 659 | **/ |
658 | static int i40evf_set_rxfh_indir(struct net_device *netdev, const u32 *indir) | 660 | static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, |
661 | const u8 *key) | ||
659 | { | 662 | { |
660 | struct i40evf_adapter *adapter = netdev_priv(netdev); | 663 | struct i40evf_adapter *adapter = netdev_priv(netdev); |
661 | struct i40e_hw *hw = &adapter->hw; | 664 | struct i40e_hw *hw = &adapter->hw; |
@@ -689,8 +692,8 @@ static const struct ethtool_ops i40evf_ethtool_ops = { | |||
689 | .get_rxnfc = i40evf_get_rxnfc, | 692 | .get_rxnfc = i40evf_get_rxnfc, |
690 | .set_rxnfc = i40evf_set_rxnfc, | 693 | .set_rxnfc = i40evf_set_rxnfc, |
691 | .get_rxfh_indir_size = i40evf_get_rxfh_indir_size, | 694 | .get_rxfh_indir_size = i40evf_get_rxfh_indir_size, |
692 | .get_rxfh_indir = i40evf_get_rxfh_indir, | 695 | .get_rxfh = i40evf_get_rxfh, |
693 | .set_rxfh_indir = i40evf_set_rxfh_indir, | 696 | .set_rxfh = i40evf_set_rxfh, |
694 | .get_channels = i40evf_get_channels, | 697 | .get_channels = i40evf_get_channels, |
695 | }; | 698 | }; |
696 | 699 | ||
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index a84297c85fb1..d8bbcf1873ca 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c | |||
@@ -2830,7 +2830,7 @@ static u32 igb_get_rxfh_indir_size(struct net_device *netdev) | |||
2830 | return IGB_RETA_SIZE; | 2830 | return IGB_RETA_SIZE; |
2831 | } | 2831 | } |
2832 | 2832 | ||
2833 | static int igb_get_rxfh_indir(struct net_device *netdev, u32 *indir) | 2833 | static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) |
2834 | { | 2834 | { |
2835 | struct igb_adapter *adapter = netdev_priv(netdev); | 2835 | struct igb_adapter *adapter = netdev_priv(netdev); |
2836 | int i; | 2836 | int i; |
@@ -2876,7 +2876,8 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter) | |||
2876 | } | 2876 | } |
2877 | } | 2877 | } |
2878 | 2878 | ||
2879 | static int igb_set_rxfh_indir(struct net_device *netdev, const u32 *indir) | 2879 | static int igb_set_rxfh(struct net_device *netdev, const u32 *indir, |
2880 | const u8 *key) | ||
2880 | { | 2881 | { |
2881 | struct igb_adapter *adapter = netdev_priv(netdev); | 2882 | struct igb_adapter *adapter = netdev_priv(netdev); |
2882 | struct e1000_hw *hw = &adapter->hw; | 2883 | struct e1000_hw *hw = &adapter->hw; |
@@ -3025,8 +3026,8 @@ static const struct ethtool_ops igb_ethtool_ops = { | |||
3025 | .get_module_info = igb_get_module_info, | 3026 | .get_module_info = igb_get_module_info, |
3026 | .get_module_eeprom = igb_get_module_eeprom, | 3027 | .get_module_eeprom = igb_get_module_eeprom, |
3027 | .get_rxfh_indir_size = igb_get_rxfh_indir_size, | 3028 | .get_rxfh_indir_size = igb_get_rxfh_indir_size, |
3028 | .get_rxfh_indir = igb_get_rxfh_indir, | 3029 | .get_rxfh = igb_get_rxfh, |
3029 | .set_rxfh_indir = igb_set_rxfh_indir, | 3030 | .set_rxfh = igb_set_rxfh, |
3030 | .get_channels = igb_get_channels, | 3031 | .get_channels = igb_get_channels, |
3031 | .set_channels = igb_set_channels, | 3032 | .set_channels = igb_set_channels, |
3032 | .begin = igb_ethtool_begin, | 3033 | .begin = igb_ethtool_begin, |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 7ba3df3cb312..c021c96294fb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | |||
@@ -564,7 +564,7 @@ static u32 mlx4_en_get_rxfh_indir_size(struct net_device *dev) | |||
564 | return priv->rx_ring_num; | 564 | return priv->rx_ring_num; |
565 | } | 565 | } |
566 | 566 | ||
567 | static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index) | 567 | static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key) |
568 | { | 568 | { |
569 | struct mlx4_en_priv *priv = netdev_priv(dev); | 569 | struct mlx4_en_priv *priv = netdev_priv(dev); |
570 | struct mlx4_en_rss_map *rss_map = &priv->rss_map; | 570 | struct mlx4_en_rss_map *rss_map = &priv->rss_map; |
@@ -582,8 +582,8 @@ static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index) | |||
582 | return err; | 582 | return err; |
583 | } | 583 | } |
584 | 584 | ||
585 | static int mlx4_en_set_rxfh_indir(struct net_device *dev, | 585 | static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index, |
586 | const u32 *ring_index) | 586 | const u8 *key) |
587 | { | 587 | { |
588 | struct mlx4_en_priv *priv = netdev_priv(dev); | 588 | struct mlx4_en_priv *priv = netdev_priv(dev); |
589 | struct mlx4_en_dev *mdev = priv->mdev; | 589 | struct mlx4_en_dev *mdev = priv->mdev; |
@@ -1224,8 +1224,8 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { | |||
1224 | .get_rxnfc = mlx4_en_get_rxnfc, | 1224 | .get_rxnfc = mlx4_en_get_rxnfc, |
1225 | .set_rxnfc = mlx4_en_set_rxnfc, | 1225 | .set_rxnfc = mlx4_en_set_rxnfc, |
1226 | .get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, | 1226 | .get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, |
1227 | .get_rxfh_indir = mlx4_en_get_rxfh_indir, | 1227 | .get_rxfh = mlx4_en_get_rxfh, |
1228 | .set_rxfh_indir = mlx4_en_set_rxfh_indir, | 1228 | .set_rxfh = mlx4_en_set_rxfh, |
1229 | .get_channels = mlx4_en_get_channels, | 1229 | .get_channels = mlx4_en_get_channels, |
1230 | .set_channels = mlx4_en_set_channels, | 1230 | .set_channels = mlx4_en_set_channels, |
1231 | .get_ts_info = mlx4_en_get_ts_info, | 1231 | .get_ts_info = mlx4_en_get_ts_info, |
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 0de8b07c24c2..74739c4b9997 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c | |||
@@ -1033,7 +1033,7 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) | |||
1033 | 0 : ARRAY_SIZE(efx->rx_indir_table)); | 1033 | 0 : ARRAY_SIZE(efx->rx_indir_table)); |
1034 | } | 1034 | } |
1035 | 1035 | ||
1036 | static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) | 1036 | static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key) |
1037 | { | 1037 | { |
1038 | struct efx_nic *efx = netdev_priv(net_dev); | 1038 | struct efx_nic *efx = netdev_priv(net_dev); |
1039 | 1039 | ||
@@ -1041,8 +1041,8 @@ static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) | |||
1041 | return 0; | 1041 | return 0; |
1042 | } | 1042 | } |
1043 | 1043 | ||
1044 | static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, | 1044 | static int efx_ethtool_set_rxfh(struct net_device *net_dev, |
1045 | const u32 *indir) | 1045 | const u32 *indir, const u8 *key) |
1046 | { | 1046 | { |
1047 | struct efx_nic *efx = netdev_priv(net_dev); | 1047 | struct efx_nic *efx = netdev_priv(net_dev); |
1048 | 1048 | ||
@@ -1125,8 +1125,8 @@ const struct ethtool_ops efx_ethtool_ops = { | |||
1125 | .get_rxnfc = efx_ethtool_get_rxnfc, | 1125 | .get_rxnfc = efx_ethtool_get_rxnfc, |
1126 | .set_rxnfc = efx_ethtool_set_rxnfc, | 1126 | .set_rxnfc = efx_ethtool_set_rxnfc, |
1127 | .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, | 1127 | .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, |
1128 | .get_rxfh_indir = efx_ethtool_get_rxfh_indir, | 1128 | .get_rxfh = efx_ethtool_get_rxfh, |
1129 | .set_rxfh_indir = efx_ethtool_set_rxfh_indir, | 1129 | .set_rxfh = efx_ethtool_set_rxfh, |
1130 | .get_ts_info = efx_ethtool_get_ts_info, | 1130 | .get_ts_info = efx_ethtool_get_ts_info, |
1131 | .get_module_info = efx_ethtool_get_module_info, | 1131 | .get_module_info = efx_ethtool_get_module_info, |
1132 | .get_module_eeprom = efx_ethtool_get_module_eeprom, | 1132 | .get_module_eeprom = efx_ethtool_get_module_eeprom, |
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 00e120296e92..9396cca93b09 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c | |||
@@ -579,7 +579,7 @@ vmxnet3_get_rss_indir_size(struct net_device *netdev) | |||
579 | } | 579 | } |
580 | 580 | ||
581 | static int | 581 | static int |
582 | vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) | 582 | vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key) |
583 | { | 583 | { |
584 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); | 584 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
585 | struct UPT1_RSSConf *rssConf = adapter->rss_conf; | 585 | struct UPT1_RSSConf *rssConf = adapter->rss_conf; |
@@ -592,7 +592,7 @@ vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) | |||
592 | } | 592 | } |
593 | 593 | ||
594 | static int | 594 | static int |
595 | vmxnet3_set_rss_indir(struct net_device *netdev, const u32 *p) | 595 | vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key) |
596 | { | 596 | { |
597 | unsigned int i; | 597 | unsigned int i; |
598 | unsigned long flags; | 598 | unsigned long flags; |
@@ -628,8 +628,8 @@ static const struct ethtool_ops vmxnet3_ethtool_ops = { | |||
628 | .get_rxnfc = vmxnet3_get_rxnfc, | 628 | .get_rxnfc = vmxnet3_get_rxnfc, |
629 | #ifdef VMXNET3_RSS | 629 | #ifdef VMXNET3_RSS |
630 | .get_rxfh_indir_size = vmxnet3_get_rss_indir_size, | 630 | .get_rxfh_indir_size = vmxnet3_get_rss_indir_size, |
631 | .get_rxfh_indir = vmxnet3_get_rss_indir, | 631 | .get_rxfh = vmxnet3_get_rss, |
632 | .set_rxfh_indir = vmxnet3_set_rss_indir, | 632 | .set_rxfh = vmxnet3_set_rss, |
633 | #endif | 633 | #endif |
634 | }; | 634 | }; |
635 | 635 | ||
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 212f537fc686..e658229fee39 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h | |||
@@ -158,19 +158,16 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) | |||
158 | * Returns zero if not supported for this specific device. | 158 | * Returns zero if not supported for this specific device. |
159 | * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. | 159 | * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. |
160 | * Returns zero if not supported for this specific device. | 160 | * Returns zero if not supported for this specific device. |
161 | * @get_rxfh_indir: Get the contents of the RX flow hash indirection table. | ||
162 | * Will not be called if @get_rxfh_indir_size returns zero. | ||
163 | * @get_rxfh: Get the contents of the RX flow hash indirection table and hash | 161 | * @get_rxfh: Get the contents of the RX flow hash indirection table and hash |
164 | * key. | 162 | * key. |
165 | * Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size | 163 | * Will only be called if one or both of @get_rxfh_indir_size and |
166 | * returns zero. | 164 | * @get_rxfh_key_size are implemented and return non-zero. |
167 | * Returns a negative error code or zero. | 165 | * Returns a negative error code or zero. |
168 | * @set_rxfh_indir: Set the contents of the RX flow hash indirection table. | 166 | * @set_rxfh: Set the contents of the RX flow hash indirection table and/or |
169 | * Will not be called if @get_rxfh_indir_size returns zero. | 167 | * hash key. In case only the indirection table or hash key is to be |
170 | * @set_rxfh: Set the contents of the RX flow hash indirection table and | 168 | * changed, the other argument will be %NULL. |
171 | * hash key. | 169 | * Will only be called if one or both of @get_rxfh_indir_size and |
172 | * Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size | 170 | * @get_rxfh_key_size are implemented and return non-zero. |
173 | * returns zero. | ||
174 | * Returns a negative error code or zero. | 171 | * Returns a negative error code or zero. |
175 | * @get_channels: Get number of channels. | 172 | * @get_channels: Get number of channels. |
176 | * @set_channels: Set number of channels. Returns a negative error code or | 173 | * @set_channels: Set number of channels. Returns a negative error code or |
@@ -244,10 +241,9 @@ struct ethtool_ops { | |||
244 | int (*reset)(struct net_device *, u32 *); | 241 | int (*reset)(struct net_device *, u32 *); |
245 | u32 (*get_rxfh_key_size)(struct net_device *); | 242 | u32 (*get_rxfh_key_size)(struct net_device *); |
246 | u32 (*get_rxfh_indir_size)(struct net_device *); | 243 | u32 (*get_rxfh_indir_size)(struct net_device *); |
247 | int (*get_rxfh)(struct net_device *, u32 *, u8 *); | 244 | int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key); |
248 | int (*set_rxfh)(struct net_device *, u32 *, u8 *); | 245 | int (*set_rxfh)(struct net_device *, const u32 *indir, |
249 | int (*get_rxfh_indir)(struct net_device *, u32 *); | 246 | const u8 *key); |
250 | int (*set_rxfh_indir)(struct net_device *, const u32 *); | ||
251 | void (*get_channels)(struct net_device *, struct ethtool_channels *); | 247 | void (*get_channels)(struct net_device *, struct ethtool_channels *); |
252 | int (*set_channels)(struct net_device *, struct ethtool_channels *); | 248 | int (*set_channels)(struct net_device *, struct ethtool_channels *); |
253 | int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); | 249 | int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); |
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index d47d31d6fa0e..e3c7a719c76b 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h | |||
@@ -850,21 +850,23 @@ struct ethtool_rxfh_indir { | |||
850 | * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. | 850 | * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. |
851 | * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH | 851 | * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH |
852 | * @rss_context: RSS context identifier. | 852 | * @rss_context: RSS context identifier. |
853 | * @indir_size: On entry, the array size of the user buffer, which may be zero. | 853 | * @indir_size: On entry, the array size of the user buffer for the |
854 | * On return from %ETHTOOL_GRSSH, the array size of the hardware | 854 | * indirection table, which may be zero, or (for %ETHTOOL_SRSSH), |
855 | * indirection table. | 855 | * %ETH_RXFH_INDIR_NO_CHANGE. On return from %ETHTOOL_GRSSH, |
856 | * @key_size: On entry, the array size of the user buffer in bytes, | 856 | * the array size of the hardware indirection table. |
857 | * which may be zero. | 857 | * @key_size: On entry, the array size of the user buffer for the hash key, |
858 | * On return from %ETHTOOL_GRSSH, the size of the RSS hash key. | 858 | * which may be zero. On return from %ETHTOOL_GRSSH, the size of the |
859 | * hardware hash key. | ||
859 | * @rsvd: Reserved for future extensions. | 860 | * @rsvd: Reserved for future extensions. |
860 | * @rss_config: RX ring/queue index for each hash value i.e., indirection table | 861 | * @rss_config: RX ring/queue index for each hash value i.e., indirection table |
861 | * of size @indir_size followed by hash key of size @key_size. | 862 | * of @indir_size __u32 elements, followed by hash key of @key_size |
863 | * bytes. | ||
862 | * | 864 | * |
863 | * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the | 865 | * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the |
864 | * size should be returned. For %ETHTOOL_SRSSH, a @indir_size of 0xDEADBEEF | 866 | * size should be returned. For %ETHTOOL_SRSSH, an @indir_size of |
865 | * means that indir table setting is not requested and a @indir_size of zero | 867 | * %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested |
866 | * means the indir table should be reset to default values. This last feature | 868 | * and a @indir_size of zero means the indir table should be reset to default |
867 | * is not supported by the original implementations. | 869 | * values. |
868 | */ | 870 | */ |
869 | struct ethtool_rxfh { | 871 | struct ethtool_rxfh { |
870 | __u32 cmd; | 872 | __u32 cmd; |
@@ -874,6 +876,7 @@ struct ethtool_rxfh { | |||
874 | __u32 rsvd[2]; | 876 | __u32 rsvd[2]; |
875 | __u32 rss_config[0]; | 877 | __u32 rss_config[0]; |
876 | }; | 878 | }; |
879 | #define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff | ||
877 | 880 | ||
878 | /** | 881 | /** |
879 | * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter | 882 | * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index aa8978ac47d2..17cb912793fa 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -561,19 +561,17 @@ static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr, | |||
561 | struct ethtool_rxnfc *rx_rings, | 561 | struct ethtool_rxnfc *rx_rings, |
562 | u32 size) | 562 | u32 size) |
563 | { | 563 | { |
564 | int ret = 0, i; | 564 | int i; |
565 | 565 | ||
566 | if (copy_from_user(indir, useraddr, size * sizeof(indir[0]))) | 566 | if (copy_from_user(indir, useraddr, size * sizeof(indir[0]))) |
567 | ret = -EFAULT; | 567 | return -EFAULT; |
568 | 568 | ||
569 | /* Validate ring indices */ | 569 | /* Validate ring indices */ |
570 | for (i = 0; i < size; i++) { | 570 | for (i = 0; i < size; i++) |
571 | if (indir[i] >= rx_rings->data) { | 571 | if (indir[i] >= rx_rings->data) |
572 | ret = -EINVAL; | 572 | return -EINVAL; |
573 | break; | 573 | |
574 | } | 574 | return 0; |
575 | } | ||
576 | return ret; | ||
577 | } | 575 | } |
578 | 576 | ||
579 | static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | 577 | static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, |
@@ -584,7 +582,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | |||
584 | int ret; | 582 | int ret; |
585 | 583 | ||
586 | if (!dev->ethtool_ops->get_rxfh_indir_size || | 584 | if (!dev->ethtool_ops->get_rxfh_indir_size || |
587 | !dev->ethtool_ops->get_rxfh_indir) | 585 | !dev->ethtool_ops->get_rxfh) |
588 | return -EOPNOTSUPP; | 586 | return -EOPNOTSUPP; |
589 | dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); | 587 | dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); |
590 | if (dev_size == 0) | 588 | if (dev_size == 0) |
@@ -610,7 +608,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | |||
610 | if (!indir) | 608 | if (!indir) |
611 | return -ENOMEM; | 609 | return -ENOMEM; |
612 | 610 | ||
613 | ret = dev->ethtool_ops->get_rxfh_indir(dev, indir); | 611 | ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL); |
614 | if (ret) | 612 | if (ret) |
615 | goto out; | 613 | goto out; |
616 | 614 | ||
@@ -634,7 +632,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, | |||
634 | int ret; | 632 | int ret; |
635 | u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]); | 633 | u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]); |
636 | 634 | ||
637 | if (!ops->get_rxfh_indir_size || !ops->set_rxfh_indir || | 635 | if (!ops->get_rxfh_indir_size || !ops->set_rxfh || |
638 | !ops->get_rxnfc) | 636 | !ops->get_rxnfc) |
639 | return -EOPNOTSUPP; | 637 | return -EOPNOTSUPP; |
640 | 638 | ||
@@ -671,7 +669,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, | |||
671 | goto out; | 669 | goto out; |
672 | } | 670 | } |
673 | 671 | ||
674 | ret = ops->set_rxfh_indir(dev, indir); | 672 | ret = ops->set_rxfh(dev, indir, NULL); |
675 | 673 | ||
676 | out: | 674 | out: |
677 | kfree(indir); | 675 | kfree(indir); |
@@ -683,11 +681,11 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev, | |||
683 | { | 681 | { |
684 | int ret; | 682 | int ret; |
685 | const struct ethtool_ops *ops = dev->ethtool_ops; | 683 | const struct ethtool_ops *ops = dev->ethtool_ops; |
686 | u32 user_indir_size = 0, user_key_size = 0; | 684 | u32 user_indir_size, user_key_size; |
687 | u32 dev_indir_size = 0, dev_key_size = 0; | 685 | u32 dev_indir_size = 0, dev_key_size = 0; |
686 | struct ethtool_rxfh rxfh; | ||
688 | u32 total_size; | 687 | u32 total_size; |
689 | u32 indir_offset, indir_bytes; | 688 | u32 indir_bytes; |
690 | u32 key_offset; | ||
691 | u32 *indir = NULL; | 689 | u32 *indir = NULL; |
692 | u8 *hkey = NULL; | 690 | u8 *hkey = NULL; |
693 | u8 *rss_config; | 691 | u8 *rss_config; |
@@ -699,33 +697,24 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev, | |||
699 | 697 | ||
700 | if (ops->get_rxfh_indir_size) | 698 | if (ops->get_rxfh_indir_size) |
701 | dev_indir_size = ops->get_rxfh_indir_size(dev); | 699 | dev_indir_size = ops->get_rxfh_indir_size(dev); |
702 | |||
703 | indir_offset = offsetof(struct ethtool_rxfh, indir_size); | ||
704 | |||
705 | if (copy_from_user(&user_indir_size, | ||
706 | useraddr + indir_offset, | ||
707 | sizeof(user_indir_size))) | ||
708 | return -EFAULT; | ||
709 | |||
710 | if (copy_to_user(useraddr + indir_offset, | ||
711 | &dev_indir_size, sizeof(dev_indir_size))) | ||
712 | return -EFAULT; | ||
713 | |||
714 | if (ops->get_rxfh_key_size) | 700 | if (ops->get_rxfh_key_size) |
715 | dev_key_size = ops->get_rxfh_key_size(dev); | 701 | dev_key_size = ops->get_rxfh_key_size(dev); |
716 | 702 | ||
717 | if ((dev_key_size + dev_indir_size) == 0) | 703 | if ((dev_key_size + dev_indir_size) == 0) |
718 | return -EOPNOTSUPP; | 704 | return -EOPNOTSUPP; |
719 | 705 | ||
720 | key_offset = offsetof(struct ethtool_rxfh, key_size); | 706 | if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) |
721 | |||
722 | if (copy_from_user(&user_key_size, | ||
723 | useraddr + key_offset, | ||
724 | sizeof(user_key_size))) | ||
725 | return -EFAULT; | 707 | return -EFAULT; |
708 | user_indir_size = rxfh.indir_size; | ||
709 | user_key_size = rxfh.key_size; | ||
726 | 710 | ||
727 | if (copy_to_user(useraddr + key_offset, | 711 | /* Check that reserved fields are 0 for now */ |
728 | &dev_key_size, sizeof(dev_key_size))) | 712 | if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) |
713 | return -EINVAL; | ||
714 | |||
715 | rxfh.indir_size = dev_indir_size; | ||
716 | rxfh.key_size = dev_key_size; | ||
717 | if (copy_to_user(useraddr, &rxfh, sizeof(rxfh))) | ||
729 | return -EFAULT; | 718 | return -EFAULT; |
730 | 719 | ||
731 | /* If the user buffer size is 0, this is just a query for the | 720 | /* If the user buffer size is 0, this is just a query for the |
@@ -770,12 +759,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | |||
770 | int ret; | 759 | int ret; |
771 | const struct ethtool_ops *ops = dev->ethtool_ops; | 760 | const struct ethtool_ops *ops = dev->ethtool_ops; |
772 | struct ethtool_rxnfc rx_rings; | 761 | struct ethtool_rxnfc rx_rings; |
773 | u32 user_indir_size = 0, dev_indir_size = 0, i; | 762 | struct ethtool_rxfh rxfh; |
774 | u32 user_key_size = 0, dev_key_size = 0; | 763 | u32 dev_indir_size = 0, dev_key_size = 0, i; |
775 | u32 *indir = NULL, indir_bytes = 0; | 764 | u32 *indir = NULL, indir_bytes = 0; |
776 | u8 *hkey = NULL; | 765 | u8 *hkey = NULL; |
777 | u8 *rss_config; | 766 | u8 *rss_config; |
778 | u32 indir_offset, key_offset; | ||
779 | u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); | 767 | u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); |
780 | 768 | ||
781 | if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || | 769 | if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || |
@@ -784,36 +772,33 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | |||
784 | 772 | ||
785 | if (ops->get_rxfh_indir_size) | 773 | if (ops->get_rxfh_indir_size) |
786 | dev_indir_size = ops->get_rxfh_indir_size(dev); | 774 | dev_indir_size = ops->get_rxfh_indir_size(dev); |
787 | |||
788 | indir_offset = offsetof(struct ethtool_rxfh, indir_size); | ||
789 | if (copy_from_user(&user_indir_size, | ||
790 | useraddr + indir_offset, | ||
791 | sizeof(user_indir_size))) | ||
792 | return -EFAULT; | ||
793 | |||
794 | if (ops->get_rxfh_key_size) | 775 | if (ops->get_rxfh_key_size) |
795 | dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); | 776 | dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); |
796 | |||
797 | if ((dev_key_size + dev_indir_size) == 0) | 777 | if ((dev_key_size + dev_indir_size) == 0) |
798 | return -EOPNOTSUPP; | 778 | return -EOPNOTSUPP; |
799 | 779 | ||
800 | key_offset = offsetof(struct ethtool_rxfh, key_size); | 780 | if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) |
801 | if (copy_from_user(&user_key_size, | ||
802 | useraddr + key_offset, | ||
803 | sizeof(user_key_size))) | ||
804 | return -EFAULT; | 781 | return -EFAULT; |
805 | 782 | ||
783 | /* Check that reserved fields are 0 for now */ | ||
784 | if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) | ||
785 | return -EINVAL; | ||
786 | |||
806 | /* If either indir or hash key is valid, proceed further. | 787 | /* If either indir or hash key is valid, proceed further. |
788 | * It is not valid to request that both be unchanged. | ||
807 | */ | 789 | */ |
808 | if ((user_indir_size && ((user_indir_size != 0xDEADBEEF) && | 790 | if ((rxfh.indir_size && |
809 | user_indir_size != dev_indir_size)) || | 791 | rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE && |
810 | (user_key_size && (user_key_size != dev_key_size))) | 792 | rxfh.indir_size != dev_indir_size) || |
793 | (rxfh.key_size && (rxfh.key_size != dev_key_size)) || | ||
794 | (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE && | ||
795 | rxfh.key_size == 0)) | ||
811 | return -EINVAL; | 796 | return -EINVAL; |
812 | 797 | ||
813 | if (user_indir_size != 0xDEADBEEF) | 798 | if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) |
814 | indir_bytes = dev_indir_size * sizeof(indir[0]); | 799 | indir_bytes = dev_indir_size * sizeof(indir[0]); |
815 | 800 | ||
816 | rss_config = kzalloc(indir_bytes + user_key_size, GFP_USER); | 801 | rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER); |
817 | if (!rss_config) | 802 | if (!rss_config) |
818 | return -ENOMEM; | 803 | return -ENOMEM; |
819 | 804 | ||
@@ -822,28 +807,29 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | |||
822 | if (ret) | 807 | if (ret) |
823 | goto out; | 808 | goto out; |
824 | 809 | ||
825 | /* user_indir_size == 0 means reset the indir table to default. | 810 | /* rxfh.indir_size == 0 means reset the indir table to default. |
826 | * user_indir_size == 0xDEADBEEF means indir setting is not requested. | 811 | * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged. |
827 | */ | 812 | */ |
828 | if (user_indir_size && user_indir_size != 0xDEADBEEF) { | 813 | if (rxfh.indir_size && |
814 | rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) { | ||
829 | indir = (u32 *)rss_config; | 815 | indir = (u32 *)rss_config; |
830 | ret = ethtool_copy_validate_indir(indir, | 816 | ret = ethtool_copy_validate_indir(indir, |
831 | useraddr + rss_cfg_offset, | 817 | useraddr + rss_cfg_offset, |
832 | &rx_rings, | 818 | &rx_rings, |
833 | user_indir_size); | 819 | rxfh.indir_size); |
834 | if (ret) | 820 | if (ret) |
835 | goto out; | 821 | goto out; |
836 | } else if (user_indir_size == 0) { | 822 | } else if (rxfh.indir_size == 0) { |
837 | indir = (u32 *)rss_config; | 823 | indir = (u32 *)rss_config; |
838 | for (i = 0; i < dev_indir_size; i++) | 824 | for (i = 0; i < dev_indir_size; i++) |
839 | indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); | 825 | indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); |
840 | } | 826 | } |
841 | 827 | ||
842 | if (user_key_size) { | 828 | if (rxfh.key_size) { |
843 | hkey = rss_config + indir_bytes; | 829 | hkey = rss_config + indir_bytes; |
844 | if (copy_from_user(hkey, | 830 | if (copy_from_user(hkey, |
845 | useraddr + rss_cfg_offset + indir_bytes, | 831 | useraddr + rss_cfg_offset + indir_bytes, |
846 | user_key_size)) { | 832 | rxfh.key_size)) { |
847 | ret = -EFAULT; | 833 | ret = -EFAULT; |
848 | goto out; | 834 | goto out; |
849 | } | 835 | } |