All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] Ethtool: Introduce hw_features field in struct netdevice
  2010-10-31  3:40 [PATCH 0/4] Ethtool: cleanup strategy Michał Mirosław
@ 2010-10-30  4:27 ` Michał Mirosław
  2010-10-30  4:28 ` [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag Michał Mirosław
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-10-30  4:27 UTC (permalink / raw)
  To: netdev
  Cc: e1000-devel, Steve Glendinning, Greg Kroah-Hartman, Rasesh Mody,
	Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers


Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 include/linux/netdevice.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 072652d..f11a5a1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -884,6 +884,8 @@ struct net_device {
 #define NETIF_F_ONE_FOR_ALL	(NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
 				 NETIF_F_SG | NETIF_F_HIGHDMA |		\
 				 NETIF_F_FRAGLIST)
+	/* ethtool-toggable features */
+	unsigned long		hw_features;
 
 	/* Interface index. Unique device identifier	*/
 	int			ifindex;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag
  2010-10-31  3:40 [PATCH 0/4] Ethtool: cleanup strategy Michał Mirosław
  2010-10-30  4:27 ` [PATCH 1/4] Ethtool: Introduce hw_features field in struct netdevice Michał Mirosław
@ 2010-10-30  4:28 ` Michał Mirosław
  2010-11-01 21:15   ` Ben Hutchings
  2010-11-02  2:24   ` Matt Carlson
  2010-10-30  8:44 ` [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags Michał Mirosław
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-10-30  4:28 UTC (permalink / raw)
  To: netdev
  Cc: e1000-devel, Steve Glendinning, Greg Kroah-Hartman, Rasesh Mody,
	Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers


Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 drivers/infiniband/hw/nes/nes_nic.c     |    3 +-
 drivers/net/8139cp.c                    |    2 +-
 drivers/net/atl1c/atl1c_ethtool.c       |    3 +-
 drivers/net/atl1e/atl1e_ethtool.c       |    2 +-
 drivers/net/atlx/atl1.c                 |    2 +-
 drivers/net/atlx/atl2.c                 |    3 +-
 drivers/net/benet/be_ethtool.c          |    2 -
 drivers/net/benet/be_main.c             |    1 +
 drivers/net/bna/bnad_ethtool.c          |    3 +-
 drivers/net/bnx2.c                      |    2 +-
 drivers/net/bnx2x/bnx2x_ethtool.c       |    3 +-
 drivers/net/bonding/bond_main.c         |    1 -
 drivers/net/chelsio/cxgb2.c             |    2 +-
 drivers/net/cxgb3/cxgb3_main.c          |    2 +-
 drivers/net/cxgb4/cxgb4_main.c          |    2 +-
 drivers/net/cxgb4vf/cxgb4vf_main.c      |    2 +-
 drivers/net/e1000/e1000_ethtool.c       |    2 +-
 drivers/net/e1000e/ethtool.c            |    3 +-
 drivers/net/enic/enic_main.c            |    3 +-
 drivers/net/forcedeth.c                 |   13 +-------
 drivers/net/fs_enet/fs_enet-main.c      |    2 +-
 drivers/net/gianfar.c                   |    1 +
 drivers/net/gianfar_ethtool.c           |    1 -
 drivers/net/ibm_newemac/core.c          |    1 -
 drivers/net/ibmveth.c                   |    2 +-
 drivers/net/igb/igb_ethtool.c           |    3 +-
 drivers/net/igbvf/ethtool.c             |    3 +-
 drivers/net/ixgb/ixgb_ethtool.c         |    2 +-
 drivers/net/ixgbe/ixgbe_ethtool.c       |    3 +-
 drivers/net/ixgbevf/ethtool.c           |    3 +-
 drivers/net/jme.c                       |    2 +-
 drivers/net/ksz884x.c                   |    3 +-
 drivers/net/loopback.c                  |    1 -
 drivers/net/mlx4/en_ethtool.c           |    2 -
 drivers/net/mlx4/en_netdev.c            |    1 +
 drivers/net/mv643xx_eth.c               |    2 +-
 drivers/net/myri10ge/myri10ge.c         |    2 +-
 drivers/net/netxen/netxen_nic_ethtool.c |    1 -
 drivers/net/netxen/netxen_nic_main.c    |    1 +
 drivers/net/qlcnic/qlcnic_ethtool.c     |    1 -
 drivers/net/qlcnic/qlcnic_main.c        |    1 +
 drivers/net/qlge/qlge_ethtool.c         |    2 -
 drivers/net/qlge/qlge_main.c            |    1 +
 drivers/net/r8169.c                     |    2 +-
 drivers/net/s2io.c                      |    2 +-
 drivers/net/sfc/efx.c                   |    1 +
 drivers/net/sfc/ethtool.c               |    2 -
 drivers/net/skge.c                      |   13 +-------
 drivers/net/sky2.c                      |    2 +-
 drivers/net/stmmac/stmmac_ethtool.c     |    3 +-
 drivers/net/tehuti.c                    |    1 -
 drivers/net/tg3.c                       |    2 +-
 drivers/net/typhoon.c                   |    2 +-
 drivers/net/ucc_geth_ethtool.c          |    2 +-
 drivers/net/veth.c                      |    3 +-
 drivers/net/via-velocity.c              |    2 +-
 drivers/net/virtio_net.c                |    2 +-
 drivers/net/vmxnet3/vmxnet3_ethtool.c   |    3 +-
 drivers/net/vxge/vxge-ethtool.c         |    3 +-
 drivers/net/xen-netfront.c              |   10 +++++--
 drivers/s390/net/qeth_l3_main.c         |    3 +-
 drivers/staging/hv/netvsc_drv.c         |    3 +-
 drivers/staging/octeon/ethernet-mdio.c  |    1 -
 include/linux/ethtool.h                 |    8 +----
 net/bridge/br_device.c                  |    6 ++--
 net/core/ethtool.c                      |   46 +++++++++++++++----------------
 net/dsa/slave.c                         |    2 +-
 67 files changed, 87 insertions(+), 134 deletions(-)

diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 3892e2c..6056913 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1585,7 +1585,6 @@ static const struct ethtool_ops nes_ethtool_ops = {
 	.set_settings = nes_netdev_set_settings,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.get_rx_csum = nes_netdev_get_rx_csum,
-	.get_sg = ethtool_op_get_sg,
 	.get_strings = nes_netdev_get_strings,
 	.get_sset_count = nes_netdev_get_sset_count,
 	.get_ethtool_stats = nes_netdev_get_ethtool_stats,
@@ -1596,7 +1595,6 @@ static const struct ethtool_ops nes_ethtool_ops = {
 	.set_pauseparam = nes_netdev_set_pauseparam,
 	.set_tx_csum = ethtool_op_set_tx_csum,
 	.set_rx_csum = nes_netdev_set_rx_csum,
-	.set_sg = ethtool_op_set_sg,
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = ethtool_op_set_tso,
 	.get_flags = ethtool_op_get_flags,
@@ -1672,6 +1670,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
 	netdev->type = ARPHRD_ETHER;
 	netdev->features = NETIF_F_HIGHDMA;
 	netdev->netdev_ops = &nes_netdev_ops;
+	netdev->hw_features |= NETIF_F_SG;
 	netdev->ethtool_ops = &nes_ethtool_ops;
 	netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);
 	nes_debug(NES_DBG_INIT, "Enabling VLAN Insert/Delete.\n");
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index ac422cd..e8cc0be 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1559,7 +1559,6 @@ static const struct ethtool_ops cp_ethtool_ops = {
 	.get_rx_csum		= cp_get_rx_csum,
 	.set_rx_csum		= cp_set_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum, /* local! */
-	.set_sg			= ethtool_op_set_sg,
 	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= cp_get_regs,
 	.get_wol		= cp_get_wol,
@@ -1958,6 +1957,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	dev->netdev_ops = &cp_netdev_ops;
 	netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
+	dev->hw_features |= NETIF_F_SG;
 	dev->ethtool_ops = &cp_ethtool_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
index 7c52150..d517223 100644
--- a/drivers/net/atl1c/atl1c_ethtool.c
+++ b/drivers/net/atl1c/atl1c_ethtool.c
@@ -308,11 +308,10 @@ static const struct ethtool_ops atl1c_ethtool_ops = {
 	.get_eeprom_len         = atl1c_get_eeprom_len,
 	.get_eeprom             = atl1c_get_eeprom,
 	.get_tx_csum            = atl1c_get_tx_csum,
-	.get_sg                 = ethtool_op_get_sg,
-	.set_sg                 = ethtool_op_set_sg,
 };
 
 void atl1c_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &atl1c_ethtool_ops);
 }
diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c
index 6943a6c..5beebd5 100644
--- a/drivers/net/atl1e/atl1e_ethtool.c
+++ b/drivers/net/atl1e/atl1e_ethtool.c
@@ -383,11 +383,11 @@ static const struct ethtool_ops atl1e_ethtool_ops = {
 	.get_eeprom             = atl1e_get_eeprom,
 	.set_eeprom             = atl1e_set_eeprom,
 	.set_tx_csum            = ethtool_op_set_tx_hw_csum,
-	.set_sg                 = ethtool_op_set_sg,
 	.set_tso                = ethtool_op_set_tso,
 };
 
 void atl1e_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &atl1e_ethtool_ops);
 }
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 43579b3..9e27bd6 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -2991,6 +2991,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
 	netdev->netdev_ops = &atl1_netdev_ops;
 	netdev->watchdog_timeo = 5 * HZ;
 
+	netdev->hw_features |= NETIF_F_SG;
 	netdev->ethtool_ops = &atl1_ethtool_ops;
 	adapter->bd_number = cards_found;
 
@@ -3677,7 +3678,6 @@ static const struct ethtool_ops atl1_ethtool_ops = {
 	.get_rx_csum		= atl1_get_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
 	.get_link		= ethtool_op_get_link,
-	.set_sg			= ethtool_op_set_sg,
 	.get_strings		= atl1_get_strings,
 	.nway_reset		= atl1_nway_reset,
 	.get_ethtool_stats	= atl1_get_ethtool_stats,
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index 35b14be..1850a00 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -2107,8 +2107,6 @@ static const struct ethtool_ops atl2_ethtool_ops = {
 	.get_eeprom		= atl2_get_eeprom,
 	.set_eeprom		= atl2_set_eeprom,
 	.get_tx_csum		= atl2_get_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
 #ifdef NETIF_F_TSO
 	.get_tso		= ethtool_op_get_tso,
 #endif
@@ -2116,6 +2114,7 @@ static const struct ethtool_ops atl2_ethtool_ops = {
 
 static void atl2_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops);
 }
 
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 0f46366..169429c 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -698,8 +698,6 @@ const struct ethtool_ops be_ethtool_ops = {
 	.set_rx_csum = be_set_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_hw_csum,
-	.get_sg = ethtool_op_get_sg,
-	.set_sg = ethtool_op_set_sg,
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = ethtool_op_set_tso,
 	.get_strings = be_get_stat_strings,
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index c36cd2f..dfa231d 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -2554,6 +2554,7 @@ static void be_netdev_init(struct net_device *netdev)
 
 	BE_SET_NETDEV_OPS(netdev, &be_netdev_ops);
 
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
 
 	for_all_rx_queues(adapter, rxo, i)
diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c
index 11fa2ea..207f57b 100644
--- a/drivers/net/bna/bnad_ethtool.c
+++ b/drivers/net/bna/bnad_ethtool.c
@@ -1261,8 +1261,6 @@ static struct ethtool_ops bnad_ethtool_ops = {
 	.set_rx_csum = bnad_set_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = bnad_set_tx_csum,
-	.get_sg = ethtool_op_get_sg,
-	.set_sg = ethtool_op_set_sg,
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = bnad_set_tso,
 	.get_strings = bnad_get_strings,
@@ -1273,5 +1271,6 @@ static struct ethtool_ops bnad_ethtool_ops = {
 void
 bnad_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
 }
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 062600b..50bdafb 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -7569,7 +7569,6 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
 	.get_rx_csum		= bnx2_get_rx_csum,
 	.set_rx_csum		= bnx2_set_rx_csum,
 	.set_tx_csum		= bnx2_set_tx_csum,
-	.set_sg			= ethtool_op_set_sg,
 	.set_tso		= bnx2_set_tso,
 	.self_test		= bnx2_self_test,
 	.get_strings		= bnx2_get_strings,
@@ -8320,6 +8319,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	dev->netdev_ops = &bnx2_netdev_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->hw_features |= NETIF_F_SG;
 	dev->ethtool_ops = &bnx2_ethtool_ops;
 
 	bp = netdev_priv(dev);
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
index d02ffbd..54955fb 100644
--- a/drivers/net/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -2082,8 +2082,6 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
 	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
 	.set_flags		= bnx2x_set_flags,
 	.get_flags		= ethtool_op_get_flags,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= bnx2x_set_tso,
 	.self_test		= bnx2x_self_test,
@@ -2095,5 +2093,6 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
 
 void bnx2x_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &bnx2x_ethtool_ops);
 }
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index bdb68a6..577b462 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4651,7 +4651,6 @@ static const struct ethtool_ops bond_ethtool_ops = {
 	.get_drvinfo		= bond_ethtool_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
 	.get_tso		= ethtool_op_get_tso,
 	.get_ufo		= ethtool_op_get_ufo,
 	.get_flags		= ethtool_op_get_flags,
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 0f71304..7f63ede 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -834,7 +834,6 @@ static const struct ethtool_ops t1_ethtool_ops = {
 	.get_rx_csum       = get_rx_csum,
 	.set_rx_csum       = set_rx_csum,
 	.set_tx_csum       = ethtool_op_set_tx_csum,
-	.set_sg            = ethtool_op_set_sg,
 	.get_link          = ethtool_op_get_link,
 	.get_strings       = get_strings,
 	.get_sset_count	   = get_sset_count,
@@ -1131,6 +1130,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 
 		netif_napi_add(netdev, &adapter->napi, t1_poll, 64);
 
+		netdev->hw_features |= NETIF_F_SG;
 		SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
 	}
 
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 407d4e2..2bc7529 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2097,7 +2097,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
 	.get_rx_csum = get_rx_csum,
 	.set_rx_csum = set_rx_csum,
 	.set_tx_csum = ethtool_op_set_tx_csum,
-	.set_sg = ethtool_op_set_sg,
 	.get_link = ethtool_op_get_link,
 	.get_strings = get_strings,
 	.phys_id = cxgb3_phys_id,
@@ -3311,6 +3310,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 
 		netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 		netdev->netdev_ops = &cxgb_netdev_ops;
+		netdev->hw_features |= NETIF_F_SG;
 		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
 	}
 
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index f17703f..ac843a3 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -2011,7 +2011,6 @@ static struct ethtool_ops cxgb_ethtool_ops = {
 	.get_rx_csum       = get_rx_csum,
 	.set_rx_csum       = set_rx_csum,
 	.set_tx_csum       = ethtool_op_set_tx_ipv6_csum,
-	.set_sg            = ethtool_op_set_sg,
 	.get_link          = ethtool_op_get_link,
 	.get_strings       = get_strings,
 	.phys_id           = identify_port,
@@ -3674,6 +3673,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 		netdev->vlan_features = netdev->features & VLAN_FEAT;
 
 		netdev->netdev_ops = &cxgb4_netdev_ops;
+		netdev->hw_features |= NETIF_F_SG;
 		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
 	}
 
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 555ecc5..ddaba63 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -1564,7 +1564,6 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = {
 	.get_rx_csum		= cxgb4vf_get_rx_csum,
 	.set_rx_csum		= cxgb4vf_set_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_ipv6_csum,
-	.set_sg			= ethtool_op_set_sg,
 	.get_link		= ethtool_op_get_link,
 	.get_strings		= cxgb4vf_get_strings,
 	.phys_id		= cxgb4vf_phys_id,
@@ -2630,6 +2629,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
 		netdev->poll_controller = cxgb4vf_poll_controller;
 #endif
 #endif
+		netdev->hw_features |= NETIF_F_SG;
 		SET_ETHTOOL_OPS(netdev, &cxgb4vf_ethtool_ops);
 
 		/*
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index f4d0922..008632c 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1925,7 +1925,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 	.set_rx_csum            = e1000_set_rx_csum,
 	.get_tx_csum            = e1000_get_tx_csum,
 	.set_tx_csum            = e1000_set_tx_csum,
-	.set_sg                 = ethtool_op_set_sg,
 	.set_tso                = e1000_set_tso,
 	.self_test              = e1000_diag_test,
 	.get_strings            = e1000_get_strings,
@@ -1938,5 +1937,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 
 void e1000_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
 }
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 8984d16..bb0bcfa 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -2036,8 +2036,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 	.set_rx_csum		= e1000_set_rx_csum,
 	.get_tx_csum		= e1000_get_tx_csum,
 	.set_tx_csum		= e1000_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= e1000_set_tso,
 	.self_test		= e1000_diag_test,
@@ -2052,5 +2050,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 
 void e1000e_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
 }
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index a466ef9..b744fca 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -413,8 +413,6 @@ static const struct ethtool_ops enic_ethtool_ops = {
 	.set_rx_csum = enic_set_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = enic_set_tx_csum,
-	.get_sg = ethtool_op_get_sg,
-	.set_sg = ethtool_op_set_sg,
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = enic_set_tso,
 	.get_coalesce = enic_get_coalesce,
@@ -2638,6 +2636,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
 		netdev->netdev_ops = &enic_netdev_ops;
 
 	netdev->watchdog_timeo = 2 * HZ;
+	netdev->hw_features |= NETIF_F_SG;
 	netdev->ethtool_ops = &enic_ethtool_ops;
 
 	netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 0fa1776..fb8c7c9 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -4658,16 +4658,6 @@ static int nv_set_tx_csum(struct net_device *dev, u32 data)
 		return -EOPNOTSUPP;
 }
 
-static int nv_set_sg(struct net_device *dev, u32 data)
-{
-	struct fe_priv *np = netdev_priv(dev);
-
-	if (np->driver_data & DEV_HAS_CHECKSUM)
-		return ethtool_op_set_sg(dev, data);
-	else
-		return -EOPNOTSUPP;
-}
-
 static int nv_get_sset_count(struct net_device *dev, int sset)
 {
 	struct fe_priv *np = netdev_priv(dev);
@@ -5047,7 +5037,6 @@ static const struct ethtool_ops ops = {
 	.get_rx_csum = nv_get_rx_csum,
 	.set_rx_csum = nv_set_rx_csum,
 	.set_tx_csum = nv_set_tx_csum,
-	.set_sg = nv_set_sg,
 	.get_strings = nv_get_strings,
 	.get_ethtool_stats = nv_get_ethtool_stats,
 	.get_sset_count = nv_get_sset_count,
@@ -5575,6 +5564,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 		dev->netdev_ops = &nv_netdev_ops_optimized;
 
 	netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP);
+	if (np->driver_data & DEV_HAS_CHECKSUM)
+		dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &ops);
 	dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
 
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index d684f18..4f1adcb 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -956,7 +956,6 @@ static const struct ethtool_ops fs_ethtool_ops = {
 	.get_msglevel = fs_get_msglevel,
 	.set_msglevel = fs_set_msglevel,
 	.set_tx_csum = ethtool_op_set_tx_csum,	/* local! */
-	.set_sg = ethtool_op_set_sg,
 	.get_regs = fs_get_regs,
 };
 
@@ -1078,6 +1077,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev,
 		netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi,
 		               fpi->napi_weight);
 
+	ndev->hw_features |= NETIF_F_SG;
 	ndev->ethtool_ops = &fs_ethtool_ops;
 
 	init_timer(&fep->phy_timer_list);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 49e4ce1..c34b1cc 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1021,6 +1021,7 @@ static int gfar_probe(struct platform_device *ofdev,
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->mtu = 1500;
 	dev->netdev_ops = &gfar_netdev_ops;
+	dev->hw_features |= NETIF_F_SG;
 	dev->ethtool_ops = &gfar_ethtool_ops;
 
 	/* Register for napi ...We are registering NAPI for each grp */
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 5c566eb..cf4a87a 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -897,7 +897,6 @@ const struct ethtool_ops gfar_ethtool_ops = {
 	.get_tx_csum = gfar_get_tx_csum,
 	.set_rx_csum = gfar_set_rx_csum,
 	.set_tx_csum = gfar_set_tx_csum,
-	.set_sg = ethtool_op_set_sg,
 	.get_msglevel = gfar_get_msglevel,
 	.set_msglevel = gfar_set_msglevel,
 #ifdef CONFIG_PM
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 385dc32..7f3ccc2 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -2211,7 +2211,6 @@ static const struct ethtool_ops emac_ethtool_ops = {
 
 	.get_link = ethtool_op_get_link,
 	.get_tx_csum = ethtool_op_get_tx_csum,
-	.get_sg = ethtool_op_get_sg,
 };
 
 static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index c454b45..7e96672 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -925,7 +925,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
 	.get_strings		= ibmveth_get_strings,
 	.get_sset_count		= ibmveth_get_sset_count,
 	.get_ethtool_stats	= ibmveth_get_ethtool_stats,
-	.set_sg			= ethtool_op_set_sg,
 };
 
 static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -1415,6 +1414,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev,
 
 	netdev->irq = dev->irq;
 	netdev->netdev_ops = &ibmveth_netdev_ops;
+	netdev->hw_features |= NETIF_F_SG;
 	netdev->ethtool_ops = &netdev_ethtool_ops;
 	SET_NETDEV_DEV(netdev, &dev->dev);
 	netdev->features |= NETIF_F_SG;
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index a70e16b..2909af5 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -2193,8 +2193,6 @@ static const struct ethtool_ops igb_ethtool_ops = {
 	.set_rx_csum            = igb_set_rx_csum,
 	.get_tx_csum            = igb_get_tx_csum,
 	.set_tx_csum            = igb_set_tx_csum,
-	.get_sg                 = ethtool_op_get_sg,
-	.set_sg                 = ethtool_op_set_sg,
 	.get_tso                = ethtool_op_get_tso,
 	.set_tso                = igb_set_tso,
 	.self_test              = igb_diag_test,
@@ -2208,5 +2206,6 @@ static const struct ethtool_ops igb_ethtool_ops = {
 
 void igb_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &igb_ethtool_ops);
 }
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
index 33add70..9bf5ea0 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -527,8 +527,6 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
 	.set_rx_csum            = igbvf_set_rx_csum,
 	.get_tx_csum		= igbvf_get_tx_csum,
 	.set_tx_csum		= igbvf_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= igbvf_set_tso,
 	.self_test		= igbvf_diag_test,
@@ -542,6 +540,7 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
 
 void igbvf_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	/* have to "undeclare" const on this struct to remove warnings */
 	SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&igbvf_ethtool_ops);
 }
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 43994c1..9623e87 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -724,7 +724,6 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
 	.set_rx_csum = ixgb_set_rx_csum,
 	.get_tx_csum = ixgb_get_tx_csum,
 	.set_tx_csum = ixgb_set_tx_csum,
-	.set_sg	= ethtool_op_set_sg,
 	.get_msglevel = ixgb_get_msglevel,
 	.set_msglevel = ixgb_set_msglevel,
 	.set_tso = ixgb_set_tso,
@@ -736,5 +735,6 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
 
 void ixgb_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &ixgb_ethtool_ops);
 }
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 3dc731c..5f1e17c 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -2287,8 +2287,6 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
 	.set_rx_csum            = ixgbe_set_rx_csum,
 	.get_tx_csum            = ixgbe_get_tx_csum,
 	.set_tx_csum            = ixgbe_set_tx_csum,
-	.get_sg                 = ethtool_op_get_sg,
-	.set_sg                 = ethtool_op_set_sg,
 	.get_msglevel           = ixgbe_get_msglevel,
 	.set_msglevel           = ixgbe_set_msglevel,
 	.get_tso                = ethtool_op_get_tso,
@@ -2307,5 +2305,6 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
 
 void ixgbe_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops);
 }
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
index 4cc817a..624375a 100644
--- a/drivers/net/ixgbevf/ethtool.c
+++ b/drivers/net/ixgbevf/ethtool.c
@@ -718,8 +718,6 @@ static struct ethtool_ops ixgbevf_ethtool_ops = {
 	.set_rx_csum            = ixgbevf_set_rx_csum,
 	.get_tx_csum            = ethtool_op_get_tx_csum,
 	.set_tx_csum            = ethtool_op_set_tx_ipv6_csum,
-	.get_sg                 = ethtool_op_get_sg,
-	.set_sg                 = ethtool_op_set_sg,
 	.get_msglevel           = ixgbevf_get_msglevel,
 	.set_msglevel           = ixgbevf_set_msglevel,
 	.get_tso                = ethtool_op_get_tso,
@@ -732,5 +730,6 @@ static struct ethtool_ops ixgbevf_ethtool_ops = {
 
 void ixgbevf_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &ixgbevf_ethtool_ops);
 }
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index d85edf3..1f7a0a7 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -2685,7 +2685,6 @@ static const struct ethtool_ops jme_ethtool_ops = {
 	.set_rx_csum		= jme_set_rx_csum,
 	.set_tx_csum		= jme_set_tx_csum,
 	.set_tso		= jme_set_tso,
-	.set_sg			= ethtool_op_set_sg,
 	.nway_reset             = jme_nway_reset,
 	.get_eeprom_len		= jme_get_eeprom_len,
 	.get_eeprom		= jme_get_eeprom,
@@ -2795,6 +2794,7 @@ jme_init_one(struct pci_dev *pdev,
 		goto err_out_release_regions;
 	}
 	netdev->netdev_ops = &jme_netdev_ops;
+	netdev->hw_features |= NETIF_F_SG;
 	netdev->ethtool_ops		= &jme_ethtool_ops;
 	netdev->watchdog_timeo		= TX_TIMEOUT;
 	netdev->features		=	NETIF_F_HW_CSUM |
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c
index 37504a3..ea69576 100644
--- a/drivers/net/ksz884x.c
+++ b/drivers/net/ksz884x.c
@@ -6662,8 +6662,6 @@ static struct ethtool_ops netdev_ethtool_ops = {
 	.set_rx_csum		= netdev_set_rx_csum,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
 };
 
 /*
@@ -7150,6 +7148,7 @@ static int __init pcidev_init(struct pci_dev *pdev,
 		}
 
 		dev->netdev_ops = &netdev_ops;
+		dev->hw_features |= NETIF_F_SG;
 		SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 		if (register_netdev(dev))
 			goto pcidev_init_reg_err;
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 2d9663a..208e9f4 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -131,7 +131,6 @@ static const struct ethtool_ops loopback_ethtool_ops = {
 	.get_link		= always_on,
 	.set_tso		= ethtool_op_set_tso,
 	.get_tx_csum		= always_on,
-	.get_sg			= always_on,
 	.get_rx_csum		= always_on,
 };
 
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index 056152b..1b355b7 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -430,8 +430,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
 	.get_tso = mlx4_en_get_tso,
 	.set_tso = mlx4_en_set_tso,
 #endif
-	.get_sg = ethtool_op_get_sg,
-	.set_sg = ethtool_op_set_sg,
 	.get_link = ethtool_op_get_link,
 	.get_rx_csum = mlx4_en_get_rx_csum,
 	.set_rx_csum = mlx4_en_set_rx_csum,
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 6d6806b..f496dbc 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -1038,6 +1038,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
 	netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
 
+	dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
 
 	/* Set defualt MAC */
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index dd2b6a7..aa3b981 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1666,7 +1666,6 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
 	.get_rx_csum		= mv643xx_eth_get_rx_csum,
 	.set_rx_csum		= mv643xx_eth_set_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
-	.set_sg			= ethtool_op_set_sg,
 	.get_strings		= mv643xx_eth_get_strings,
 	.get_ethtool_stats	= mv643xx_eth_get_ethtool_stats,
 	.get_flags		= ethtool_op_get_flags,
@@ -2910,6 +2909,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
 	if (mp->phy != NULL)
 		phy_init(mp, pd->speed, pd->duplex);
 
+	dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
 
 	init_pscr(mp, pd->speed, pd->duplex);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 8524cc4..3696bba 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1951,7 +1951,6 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
 	.get_rx_csum = myri10ge_get_rx_csum,
 	.set_rx_csum = myri10ge_set_rx_csum,
 	.set_tx_csum = ethtool_op_set_tx_hw_csum,
-	.set_sg = ethtool_op_set_sg,
 	.set_tso = myri10ge_set_tso,
 	.get_link = ethtool_op_get_link,
 	.get_strings = myri10ge_get_strings,
@@ -3998,6 +3997,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		    (unsigned long)mgp);
 
 	spin_lock_init(&mgp->stats_lock);
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops);
 	INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog);
 	status = register_netdev(netdev);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index b30de24..f22f0a7 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -926,7 +926,6 @@ const struct ethtool_ops netxen_nic_ethtool_ops = {
 	.set_pauseparam = netxen_nic_set_pauseparam,
 	.get_tx_csum = netxen_nic_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_csum,
-	.set_sg = ethtool_op_set_sg,
 	.get_tso = netxen_nic_get_tso,
 	.set_tso = netxen_nic_set_tso,
 	.get_wol = netxen_nic_get_wol,
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 35ae1aa..4b2874c 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -1210,6 +1210,7 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
 
 	netxen_nic_change_mtu(netdev, netdev->mtu);
 
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
 
 	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index ec21d24..ceba22d 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -1166,7 +1166,6 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
 	.set_pauseparam = qlcnic_set_pauseparam,
 	.get_tx_csum = qlcnic_get_tx_csum,
 	.set_tx_csum = qlcnic_set_tx_csum,
-	.set_sg = ethtool_op_set_sg,
 	.get_tso = qlcnic_get_tso,
 	.set_tso = qlcnic_set_tso,
 	.get_wol = qlcnic_get_wol,
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 7a298cd..30ed19a 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -1425,6 +1425,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
 
 	qlcnic_change_mtu(netdev, netdev->mtu);
 
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
 
 	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 4892d64..d8b2d3f 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -698,8 +698,6 @@ const struct ethtool_ops qlge_ethtool_ops = {
 	.set_rx_csum = ql_set_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_csum,
-	.get_sg = ethtool_op_get_sg,
-	.set_sg = ethtool_op_set_sg,
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = ql_set_tso,
 	.get_coalesce = ql_get_coalesce,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index c30e0fe..75b708c 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -4713,6 +4713,7 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
 	ndev->irq = pdev->irq;
 
 	ndev->netdev_ops = &qlge_netdev_ops;
+	ndev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops);
 	ndev->watchdog_timeo = 10 * HZ;
 
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index d88ce9f..746e296 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1277,7 +1277,6 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
 	.get_rx_csum		= rtl8169_get_rx_csum,
 	.set_rx_csum		= rtl8169_set_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
-	.set_sg			= ethtool_op_set_sg,
 	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= rtl8169_get_regs,
 	.get_wol		= rtl8169_get_wol,
@@ -3173,6 +3172,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
+	dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
 	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
 	dev->irq = pdev->irq;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index ecc25aa..e447a4d 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -6769,7 +6769,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
 	.set_tx_csum = s2io_ethtool_op_set_tx_csum,
 	.set_flags = s2io_ethtool_set_flags,
 	.get_flags = ethtool_op_get_flags,
-	.set_sg = ethtool_op_set_sg,
 	.get_tso = s2io_ethtool_op_get_tso,
 	.set_tso = s2io_ethtool_op_set_tso,
 	.set_ufo = ethtool_op_set_ufo,
@@ -8034,6 +8033,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 
 	/*  Driver entry points */
 	dev->netdev_ops = &s2io_netdev_ops;
+	dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 	dev->features |= NETIF_F_LRO;
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 05df20e..b6b0f5d 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1882,6 +1882,7 @@ static int efx_register_netdev(struct efx_nic *efx)
 	net_dev->watchdog_timeo = 5 * HZ;
 	net_dev->irq = efx->pci_dev->irq;
 	net_dev->netdev_ops = &efx_netdev_ops;
+	net_dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
 
 	/* Clear MAC statistics */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index edb9d16..c994666 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -1130,8 +1130,6 @@ const struct ethtool_ops efx_ethtool_ops = {
 	.get_tx_csum		= ethtool_op_get_tx_csum,
 	/* Need to enable/disable IPv6 too */
 	.set_tx_csum		= efx_ethtool_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
 	.get_tso		= ethtool_op_get_tso,
 	/* Need to enable/disable TSO-IPv6 too */
 	.set_tso		= efx_ethtool_set_tso,
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index bfec2e0..ac153bd 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -537,16 +537,6 @@ static int skge_nway_reset(struct net_device *dev)
 	return 0;
 }
 
-static int skge_set_sg(struct net_device *dev, u32 data)
-{
-	struct skge_port *skge = netdev_priv(dev);
-	struct skge_hw *hw = skge->hw;
-
-	if (hw->chip_id == CHIP_ID_GENESIS && data)
-		return -EOPNOTSUPP;
-	return ethtool_op_set_sg(dev, data);
-}
-
 static int skge_set_tx_csum(struct net_device *dev, u32 data)
 {
 	struct skge_port *skge = netdev_priv(dev);
@@ -925,7 +915,6 @@ static const struct ethtool_ops skge_ethtool_ops = {
 	.set_pauseparam = skge_set_pauseparam,
 	.get_coalesce	= skge_get_coalesce,
 	.set_coalesce	= skge_set_coalesce,
-	.set_sg		= skge_set_sg,
 	.set_tx_csum	= skge_set_tx_csum,
 	.get_rx_csum	= skge_get_rx_csum,
 	.set_rx_csum	= skge_set_rx_csum,
@@ -3811,6 +3800,8 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
 
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->netdev_ops = &skge_netdev_ops;
+	if (hw->chip_id != CHIP_ID_GENESIS)
+		dev->hw_features |= NETIF_F_SG;
 	dev->ethtool_ops = &skge_ethtool_ops;
 	dev->watchdog_timeo = TX_WATCHDOG;
 	dev->irq = hw->pdev->irq;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index d657708..a06bb6e 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -4216,7 +4216,6 @@ static const struct ethtool_ops sky2_ethtool_ops = {
 	.get_eeprom_len	= sky2_get_eeprom_len,
 	.get_eeprom	= sky2_get_eeprom,
 	.set_eeprom	= sky2_set_eeprom,
-	.set_sg 	= ethtool_op_set_sg,
 	.set_tx_csum	= sky2_set_tx_csum,
 	.set_tso	= sky2_set_tso,
 	.get_rx_csum	= sky2_get_rx_csum,
@@ -4550,6 +4549,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
 
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->irq = hw->pdev->irq;
+	dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops);
 	dev->watchdog_timeo = TX_WATCHDOG;
 	dev->netdev_ops = &sky2_netdev_ops[port];
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
index 6d65482..4461a9e 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -371,8 +371,6 @@ static struct ethtool_ops stmmac_ethtool_ops = {
 	.get_rx_csum = stmmac_ethtool_get_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = stmmac_ethtool_set_tx_csum,
-	.get_sg = ethtool_op_get_sg,
-	.set_sg = ethtool_op_set_sg,
 	.get_pauseparam = stmmac_get_pauseparam,
 	.set_pauseparam = stmmac_set_pauseparam,
 	.get_ethtool_stats = stmmac_get_ethtool_stats,
@@ -386,5 +384,6 @@ static struct ethtool_ops stmmac_ethtool_ops = {
 
 void stmmac_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops);
 }
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 8b3dc1e..ed6dc44 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -2426,7 +2426,6 @@ static void bdx_set_ethtool_ops(struct net_device *netdev)
 		.set_ringparam = bdx_set_ringparam,
 		.get_rx_csum = bdx_get_rx_csum,
 		.get_tx_csum = bdx_get_tx_csum,
-		.get_sg = ethtool_op_get_sg,
 		.get_tso = ethtool_op_get_tso,
 		.get_strings = bdx_get_strings,
 		.get_sset_count = bdx_get_sset_count,
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 30ccbb6..b07e2d1 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -11306,7 +11306,6 @@ static const struct ethtool_ops tg3_ethtool_ops = {
 	.get_rx_csum		= tg3_get_rx_csum,
 	.set_rx_csum		= tg3_set_rx_csum,
 	.set_tx_csum		= tg3_set_tx_csum,
-	.set_sg			= ethtool_op_set_sg,
 	.set_tso		= tg3_set_tso,
 	.self_test		= tg3_self_test,
 	.get_strings		= tg3_get_strings,
@@ -14681,6 +14680,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 	tp->rx_pending = TG3_DEF_RX_RING_PENDING;
 	tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
 
+	dev->hw_features |= NETIF_F_SG;
 	dev->ethtool_ops = &tg3_ethtool_ops;
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
 	dev->irq = pdev->irq;
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 5b83c3f..4b49dd7 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1191,7 +1191,6 @@ static const struct ethtool_ops typhoon_ethtool_ops = {
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= typhoon_get_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
-	.set_sg			= ethtool_op_set_sg,
 	.set_tso		= ethtool_op_set_tso,
 	.get_ringparam		= typhoon_get_ringparam,
 	.set_flags		= typhoon_set_flags,
@@ -2480,6 +2479,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
 	dev->watchdog_timeo	= TX_TIMEOUT;
 
+	dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &typhoon_ethtool_ops);
 
 	/* We can handle scatter gather, up to 16 entries, and
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
index 6f92e48..fa3e464 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -410,7 +410,6 @@ static const struct ethtool_ops uec_ethtool_ops = {
 	.set_ringparam          = uec_set_ringparam,
 	.get_pauseparam         = uec_get_pauseparam,
 	.set_pauseparam         = uec_set_pauseparam,
-	.set_sg                 = ethtool_op_set_sg,
 	.get_sset_count		= uec_get_sset_count,
 	.get_strings            = uec_get_strings,
 	.get_ethtool_stats      = uec_get_ethtool_stats,
@@ -420,5 +419,6 @@ static const struct ethtool_ops uec_ethtool_ops = {
 
 void uec_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &uec_ethtool_ops);
 }
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 0bbc0c3..d00db8a 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -138,8 +138,6 @@ static const struct ethtool_ops veth_ethtool_ops = {
 	.set_rx_csum		= veth_set_rx_csum,
 	.get_tx_csum		= veth_get_tx_csum,
 	.set_tx_csum		= veth_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
 	.get_strings		= veth_get_strings,
 	.get_sset_count		= veth_get_sset_count,
 	.get_ethtool_stats	= veth_get_ethtool_stats,
@@ -299,6 +297,7 @@ static void veth_setup(struct net_device *dev)
 	ether_setup(dev);
 
 	dev->netdev_ops = &veth_netdev_ops;
+	dev->hw_features |= NETIF_F_SG;
 	dev->ethtool_ops = &veth_ethtool_ops;
 	dev->features |= NETIF_F_LLTX;
 	dev->destructor = veth_dev_free;
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index cab96ad..a6389ef 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -2838,6 +2838,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
 
 	dev->irq = pdev->irq;
 	dev->netdev_ops = &velocity_netdev_ops;
+	dev->hw_features |= NETIF_F_SG;
 	dev->ethtool_ops = &velocity_ethtool_ops;
 	netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
 
@@ -3454,7 +3455,6 @@ static const struct ethtool_ops velocity_ethtool_ops = {
 	.set_wol	=	velocity_ethtool_set_wol,
 	.get_msglevel	=	velocity_get_msglevel,
 	.set_msglevel	=	velocity_set_msglevel,
-	.set_sg 	=	ethtool_op_set_sg,
 	.get_link	=	velocity_get_link,
 	.get_coalesce	=	velocity_get_coalesce,
 	.set_coalesce	=	velocity_set_coalesce,
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index bb6b67f..b332e92 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -818,7 +818,6 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
 
 static const struct ethtool_ops virtnet_ethtool_ops = {
 	.set_tx_csum = virtnet_set_tx_csum,
-	.set_sg = ethtool_op_set_sg,
 	.set_tso = ethtool_op_set_tso,
 	.set_ufo = ethtool_op_set_ufo,
 	.get_link = ethtool_op_get_link,
@@ -903,6 +902,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 	/* Set up network device as normal. */
 	dev->netdev_ops = &virtnet_netdev;
 	dev->features = NETIF_F_HIGHDMA;
+	dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
 	SET_NETDEV_DEV(dev, &vdev->dev);
 
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index b79070b..9925d2b 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -547,8 +547,6 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
 	.set_rx_csum       = vmxnet3_set_rx_csum,
 	.get_tx_csum       = ethtool_op_get_tx_csum,
 	.set_tx_csum       = ethtool_op_set_tx_hw_csum,
-	.get_sg            = ethtool_op_get_sg,
-	.set_sg            = ethtool_op_set_sg,
 	.get_tso           = ethtool_op_get_tso,
 	.set_tso           = ethtool_op_set_tso,
 	.get_strings       = vmxnet3_get_strings,
@@ -562,5 +560,6 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
 
 void vmxnet3_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &vmxnet3_ethtool_ops);
 }
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
index b67746e..3c7ccd0 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/vxge/vxge-ethtool.c
@@ -1132,8 +1132,6 @@ static const struct ethtool_ops vxge_ethtool_ops = {
 	.set_rx_csum		= vxge_set_rx_csum,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= vxge_ethtool_op_set_tso,
 	.get_strings		= vxge_ethtool_get_strings,
@@ -1144,5 +1142,6 @@ static const struct ethtool_ops vxge_ethtool_ops = {
 
 void vxge_initialize_ethtool_ops(struct net_device *ndev)
 {
+	ndev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(ndev, &vxge_ethtool_ops);
 }
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 458bb57..e494cc2 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1178,6 +1178,7 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev
 	netif_napi_add(netdev, &np->napi, xennet_poll, 64);
 	netdev->features        = NETIF_F_IP_CSUM;
 
+	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
 	SET_NETDEV_DEV(netdev, &dev->dev);
 
@@ -1491,7 +1492,7 @@ static int xennet_set_sg(struct net_device *dev, u32 data)
 	} else if (dev->mtu > ETH_DATA_LEN)
 		dev->mtu = ETH_DATA_LEN;
 
-	return ethtool_op_set_sg(dev, data);
+	return 0;
 }
 
 static int xennet_set_tso(struct net_device *dev, u32 data)
@@ -1516,13 +1517,16 @@ static void xennet_set_features(struct net_device *dev)
 	dev->features &= ~NETIF_F_GSO_MASK;
 	dev->features |= NETIF_F_GSO_ROBUST;
 	xennet_set_sg(dev, 0);
+	dev->features &= ~NETIF_F_SG;
 
 	/* We need checksum offload to enable scatter/gather and TSO. */
 	if (!(dev->features & NETIF_F_IP_CSUM))
 		return;
 
-	if (!xennet_set_sg(dev, 1))
+	if (!xennet_set_sg(dev, 1)) {
+		dev->features |= NETIF_F_SG;
 		xennet_set_tso(dev, 1);
+	}
 }
 
 static int xennet_connect(struct net_device *dev)
@@ -1635,7 +1639,7 @@ static void netback_changed(struct xenbus_device *dev,
 static const struct ethtool_ops xennet_ethtool_ops =
 {
 	.set_tx_csum = ethtool_op_set_tx_csum,
-	.set_sg = xennet_set_sg,
+	.hw_set_sg = xennet_set_sg,
 	.set_tso = xennet_set_tso,
 	.get_link = ethtool_op_get_link,
 };
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 74d1401..5fd646f 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3254,8 +3254,6 @@ static const struct ethtool_ops qeth_l3_ethtool_ops = {
 	.set_tx_csum = qeth_l3_ethtool_set_tx_csum,
 	.get_rx_csum = qeth_l3_ethtool_get_rx_csum,
 	.set_rx_csum = qeth_l3_ethtool_set_rx_csum,
-	.get_sg      = ethtool_op_get_sg,
-	.set_sg      = ethtool_op_set_sg,
 	.get_tso     = ethtool_op_get_tso,
 	.set_tso     = qeth_l3_ethtool_set_tso,
 	.get_strings = qeth_core_get_strings,
@@ -3357,6 +3355,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
 	card->dev->ml_priv = card;
 	card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
 	card->dev->mtu = card->info.initial_mtu;
+	card->dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops);
 	card->dev->features |=	NETIF_F_HW_VLAN_TX |
 				NETIF_F_HW_VLAN_RX |
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 1415352..3118ca5 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -317,8 +317,6 @@ static void netvsc_get_drvinfo(struct net_device *net,
 
 static const struct ethtool_ops ethtool_ops = {
 	.get_drvinfo	= netvsc_get_drvinfo,
-	.get_sg		= ethtool_op_get_sg,
-	.set_sg		= ethtool_op_set_sg,
 	.get_link	= ethtool_op_get_link,
 };
 
@@ -392,6 +390,7 @@ static int netvsc_probe(struct device *device)
 	/* TODO: Add GSO and Checksum offload */
 	net->features = NETIF_F_SG;
 
+	net->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(net, &ethtool_ops);
 	SET_NETDEV_DEV(net, device);
 
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 10a82ef..7ad58bf 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -91,7 +91,6 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
 	.set_settings = cvm_oct_set_settings,
 	.nway_reset = cvm_oct_nway_reset,
 	.get_link = ethtool_op_get_link,
-	.get_sg = ethtool_op_get_sg,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 };
 
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 6628a50..6b26e3e 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -548,8 +548,6 @@ u32 ethtool_op_get_tx_csum(struct net_device *dev);
 int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
 int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
 int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data);
-u32 ethtool_op_get_sg(struct net_device *dev);
-int ethtool_op_set_sg(struct net_device *dev, u32 data);
 u32 ethtool_op_get_tso(struct net_device *dev);
 int ethtool_op_set_tso(struct net_device *dev, u32 data);
 u32 ethtool_op_get_ufo(struct net_device *dev);
@@ -582,8 +580,7 @@ void ethtool_ntuple_flush(struct net_device *dev);
  * set_rx_csum: Turn receive checksum on or off
  * get_tx_csum: Report whether transmit checksums are turned on or off
  * set_tx_csum: Turn transmit checksums on or off
- * get_sg: Report whether scatter-gather is enabled
- * set_sg: Turn scatter-gather on or off
+ * hw_set_sg: Turn scatter-gather on or off
  * get_tso: Report whether TCP segmentation offload is enabled
  * set_tso: Turn TCP segmentation offload on or off
  * get_ufo: Report whether UDP fragmentation offload is enabled
@@ -648,8 +645,7 @@ struct ethtool_ops {
 	int	(*set_rx_csum)(struct net_device *, u32);
 	u32	(*get_tx_csum)(struct net_device *);
 	int	(*set_tx_csum)(struct net_device *, u32);
-	u32	(*get_sg)(struct net_device *);
-	int	(*set_sg)(struct net_device *, u32);
+	int	(*hw_set_sg)(struct net_device *, u32);
 	u32	(*get_tso)(struct net_device *);
 	int	(*set_tso)(struct net_device *, u32);
 	void	(*self_test)(struct net_device *, struct ethtool_test *, u64 *);
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 17cb0b6..3d12ebc 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -183,7 +183,7 @@ static int br_set_sg(struct net_device *dev, u32 data)
 		br->feature_mask &= ~NETIF_F_SG;
 
 	br_features_recompute(br);
-	return 0;
+	return 1;
 }
 
 static int br_set_tso(struct net_device *dev, u32 data)
@@ -302,8 +302,7 @@ static const struct ethtool_ops br_ethtool_ops = {
 	.get_link	= ethtool_op_get_link,
 	.get_tx_csum	= ethtool_op_get_tx_csum,
 	.set_tx_csum 	= br_set_tx_csum,
-	.get_sg		= ethtool_op_get_sg,
-	.set_sg		= br_set_sg,
+	.hw_set_sg	= br_set_sg,
 	.get_tso	= ethtool_op_get_tso,
 	.set_tso	= br_set_tso,
 	.get_ufo	= ethtool_op_get_ufo,
@@ -343,6 +342,7 @@ void br_dev_setup(struct net_device *dev)
 
 	dev->netdev_ops = &br_netdev_ops;
 	dev->destructor = br_dev_free;
+	dev->hw_features = NETIF_F_SG;
 	SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
 	dev->tx_queue_len = 0;
 	dev->priv_flags = IFF_EBRIDGE;
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 956a9f4..017667c 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -78,23 +78,6 @@ int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
 }
 EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
 
-u32 ethtool_op_get_sg(struct net_device *dev)
-{
-	return (dev->features & NETIF_F_SG) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_sg);
-
-int ethtool_op_set_sg(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= NETIF_F_SG;
-	else
-		dev->features &= ~NETIF_F_SG;
-
-	return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_sg);
-
 u32 ethtool_op_get_tso(struct net_device *dev)
 {
 	return (dev->features & NETIF_F_TSO) != 0;
@@ -1073,6 +1056,11 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
 	return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
 }
 
+static u32 ethtool_get_sg(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_SG) != 0;
+}
+
 static int __ethtool_set_sg(struct net_device *dev, u32 data)
 {
 	int err;
@@ -1088,7 +1076,19 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
 		if (err)
 			return err;
 	}
-	return dev->ethtool_ops->set_sg(dev, data);
+
+	if (dev->ethtool_ops->hw_set_sg) {
+		err = dev->ethtool_ops->hw_set_sg(dev, data);
+		if (err)
+			return min(err, 0);
+	}
+
+	if (data)
+		dev->features |= NETIF_F_SG;
+	else
+		dev->features &= ~NETIF_F_SG;
+
+	return 0;
 }
 
 static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
@@ -1102,7 +1102,7 @@ static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
 	if (copy_from_user(&edata, useraddr, sizeof(edata)))
 		return -EFAULT;
 
-	if (!edata.data && dev->ethtool_ops->set_sg) {
+	if (!edata.data && (dev->hw_features & NETIF_F_SG)) {
 		err = __ethtool_set_sg(dev, 0);
 		if (err)
 			return err;
@@ -1122,7 +1122,7 @@ static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr)
 	if (copy_from_user(&edata, useraddr, sizeof(edata)))
 		return -EFAULT;
 
-	if (!edata.data && dev->ethtool_ops->set_sg)
+	if (!edata.data && (dev->hw_features & NETIF_F_SG))
 		dev->features &= ~NETIF_F_GRO;
 
 	return dev->ethtool_ops->set_rx_csum(dev, edata.data);
@@ -1132,7 +1132,7 @@ static int ethtool_set_sg(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_value edata;
 
-	if (!dev->ethtool_ops->set_sg)
+	if (!(dev->hw_features & NETIF_F_SG))
 		return -EOPNOTSUPP;
 
 	if (copy_from_user(&edata, useraddr, sizeof(edata)))
@@ -1575,9 +1575,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 		break;
 	case ETHTOOL_GSG:
 		rc = ethtool_get_value(dev, useraddr, ethcmd,
-				       (dev->ethtool_ops->get_sg ?
-					dev->ethtool_ops->get_sg :
-					ethtool_op_get_sg));
+					ethtool_get_sg);
 		break;
 	case ETHTOOL_SSG:
 		rc = ethtool_set_sg(dev, useraddr);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 64ca2a6..f40660c 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -288,7 +288,6 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
 	.get_drvinfo		= dsa_slave_get_drvinfo,
 	.nway_reset		= dsa_slave_nway_reset,
 	.get_link		= dsa_slave_get_link,
-	.set_sg			= ethtool_op_set_sg,
 	.get_strings		= dsa_slave_get_strings,
 	.get_ethtool_stats	= dsa_slave_get_ethtool_stats,
 	.get_sset_count		= dsa_slave_get_sset_count,
@@ -350,6 +349,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 		return slave_dev;
 
 	slave_dev->features = master->vlan_features;
+	slave_dev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(slave_dev, &dsa_slave_ethtool_ops);
 	memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN);
 	slave_dev->tx_queue_len = 0;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags
  2010-10-31  3:40 [PATCH 0/4] Ethtool: cleanup strategy Michał Mirosław
  2010-10-30  4:27 ` [PATCH 1/4] Ethtool: Introduce hw_features field in struct netdevice Michał Mirosław
  2010-10-30  4:28 ` [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag Michał Mirosław
@ 2010-10-30  8:44 ` Michał Mirosław
  2010-11-01 21:25   ` Ben Hutchings
  2010-11-02  2:49   ` Matt Carlson
  2010-10-31  0:09 ` [PATCH 4/4] Ethtool: convert get_tx_csum/set_tx_csum " Michał Mirosław
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-10-30  8:44 UTC (permalink / raw)
  To: netdev
  Cc: e1000-devel, Steve Glendinning, Greg Kroah-Hartman, Rasesh Mody,
	Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers


Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 drivers/infiniband/hw/nes/nes_nic.c          |    4 +-
 drivers/infiniband/ulp/ipoib/ipoib_ethtool.c |   10 ++--
 drivers/net/8139cp.c                         |    3 +-
 drivers/net/atl1e/atl1e_ethtool.c            |    3 +-
 drivers/net/atlx/atl1.c                      |    2 +-
 drivers/net/atlx/atl2.c                      |    3 -
 drivers/net/benet/be_ethtool.c               |    2 -
 drivers/net/benet/be_main.c                  |    2 +-
 drivers/net/bna/bnad_ethtool.c               |   20 +---------
 drivers/net/bnx2.c                           |   18 +--------
 drivers/net/bnx2x/bnx2x_ethtool.c            |   16 +-------
 drivers/net/bonding/bond_main.c              |    1 -
 drivers/net/chelsio/cxgb2.c                  |   12 +-----
 drivers/net/cxgb3/cxgb3_main.c               |    3 +-
 drivers/net/cxgb4/cxgb4_main.c               |   12 +-----
 drivers/net/cxgb4vf/cxgb4vf_main.c           |   14 +------
 drivers/net/e1000/e1000.h                    |    1 -
 drivers/net/e1000/e1000_ethtool.c            |   28 +++-----------
 drivers/net/e1000e/ethtool.c                 |   12 +-----
 drivers/net/ehea/ehea_ethtool.c              |    2 +-
 drivers/net/enic/enic_main.c                 |   11 +----
 drivers/net/forcedeth.c                      |   13 +------
 drivers/net/igb/igb_ethtool.c                |   20 +---------
 drivers/net/igbvf/ethtool.c                  |   20 +---------
 drivers/net/ixgb/ixgb_ethtool.c              |   13 +------
 drivers/net/ixgbe/ixgbe_ethtool.c            |   15 +-------
 drivers/net/ixgbevf/ethtool.c                |   17 +--------
 drivers/net/jme.c                            |    9 ++--
 drivers/net/loopback.c                       |    2 +-
 drivers/net/mlx4/en_ethtool.c                |   19 ++-------
 drivers/net/mlx4/en_netdev.c                 |    1 +
 drivers/net/myri10ge/myri10ge.c              |   14 +------
 drivers/net/netxen/netxen_nic_ethtool.c      |   26 -------------
 drivers/net/netxen/netxen_nic_main.c         |    4 +-
 drivers/net/qlcnic/qlcnic_ethtool.c          |   20 ----------
 drivers/net/qlcnic/qlcnic_main.c             |    1 +
 drivers/net/qlge/qlge_ethtool.c              |   15 -------
 drivers/net/qlge/qlge_main.c                 |    1 +
 drivers/net/r8169.c                          |    3 +-
 drivers/net/s2io.c                           |   18 +--------
 drivers/net/sfc/efx.c                        |    4 +-
 drivers/net/sfc/ethtool.c                    |   20 ----------
 drivers/net/sky2.c                           |    6 +-
 drivers/net/stmmac/stmmac_ethtool.c          |    4 +-
 drivers/net/tehuti.c                         |    1 -
 drivers/net/tg3.c                            |   38 ++++++++++---------
 drivers/net/typhoon.c                        |    3 +-
 drivers/net/usb/smsc75xx.c                   |   17 +-------
 drivers/net/virtio_net.c                     |    3 +-
 drivers/net/vmxnet3/vmxnet3_ethtool.c        |    4 +-
 drivers/net/vxge/vxge-ethtool.c              |   13 +------
 drivers/net/xen-netfront.c                   |    9 ++--
 drivers/s390/net/qeth_l3_main.c              |    7 +--
 include/linux/ethtool.h                      |    8 +---
 include/linux/netdevice.h                    |    2 +
 net/8021q/vlan_dev.c                         |    5 +-
 net/bridge/br_device.c                       |    7 +--
 net/core/ethtool.c                           |   52 +++++++++++++-------------
 58 files changed, 132 insertions(+), 481 deletions(-)

diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 6056913..04af96a 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1595,8 +1595,6 @@ static const struct ethtool_ops nes_ethtool_ops = {
 	.set_pauseparam = nes_netdev_set_pauseparam,
 	.set_tx_csum = ethtool_op_set_tx_csum,
 	.set_rx_csum = nes_netdev_set_rx_csum,
-	.get_tso = ethtool_op_get_tso,
-	.set_tso = ethtool_op_set_tso,
 	.get_flags = ethtool_op_get_flags,
 	.set_flags = nes_netdev_set_flags,
 };
@@ -1670,7 +1668,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
 	netdev->type = ARPHRD_ETHER;
 	netdev->features = NETIF_F_HIGHDMA;
 	netdev->netdev_ops = &nes_netdev_ops;
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	netdev->ethtool_ops = &nes_ethtool_ops;
 	netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);
 	nes_debug(NES_DBG_INIT, "Enabling VLAN Insert/Delete.\n");
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 1a1657c..6fb3cf4 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -58,13 +58,12 @@ static int ipoib_set_tso(struct net_device *dev, u32 data)
 		    (dev->features & NETIF_F_SG) &&
 		    (priv->hca_caps & IB_DEVICE_UD_TSO)) {
 			dev->features |= NETIF_F_TSO;
+			return 1;
 		} else {
 			ipoib_warn(priv, "can't set TSO on\n");
-			return -EOPNOTSUPP;
+			return -EINVAL;
 		}
-	} else
-		dev->features &= ~NETIF_F_TSO;
-
+	}
 	return 0;
 }
 
@@ -155,7 +154,7 @@ static int ipoib_set_flags(struct net_device *dev, u32 flags)
 static const struct ethtool_ops ipoib_ethtool_ops = {
 	.get_drvinfo		= ipoib_get_drvinfo,
 	.get_rx_csum		= ipoib_get_rx_csum,
-	.set_tso		= ipoib_set_tso,
+	.hw_set_tso		= ipoib_set_tso,
 	.get_coalesce		= ipoib_get_coalesce,
 	.set_coalesce		= ipoib_set_coalesce,
 	.get_flags		= ethtool_op_get_flags,
@@ -167,5 +166,6 @@ static const struct ethtool_ops ipoib_ethtool_ops = {
 
 void ipoib_set_ethtool_ops(struct net_device *dev)
 {
+	dev->hw_features |= NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &ipoib_ethtool_ops);
 }
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index e8cc0be..0fd2867 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1559,7 +1559,6 @@ static const struct ethtool_ops cp_ethtool_ops = {
 	.get_rx_csum		= cp_get_rx_csum,
 	.set_rx_csum		= cp_set_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum, /* local! */
-	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= cp_get_regs,
 	.get_wol		= cp_get_wol,
 	.set_wol		= cp_set_wol,
@@ -1957,7 +1956,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	dev->netdev_ops = &cp_netdev_ops;
 	netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	dev->ethtool_ops = &cp_ethtool_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c
index 5beebd5..1485797 100644
--- a/drivers/net/atl1e/atl1e_ethtool.c
+++ b/drivers/net/atl1e/atl1e_ethtool.c
@@ -383,11 +383,10 @@ static const struct ethtool_ops atl1e_ethtool_ops = {
 	.get_eeprom             = atl1e_get_eeprom,
 	.set_eeprom             = atl1e_set_eeprom,
 	.set_tx_csum            = ethtool_op_set_tx_hw_csum,
-	.set_tso                = ethtool_op_set_tso,
 };
 
 void atl1e_set_ethtool_ops(struct net_device *netdev)
 {
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &atl1e_ethtool_ops);
 }
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 9e27bd6..814a06c 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -2992,6 +2992,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
 	netdev->watchdog_timeo = 5 * HZ;
 
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO;
 	netdev->ethtool_ops = &atl1_ethtool_ops;
 	adapter->bd_number = cards_found;
 
@@ -3682,5 +3683,4 @@ static const struct ethtool_ops atl1_ethtool_ops = {
 	.nway_reset		= atl1_nway_reset,
 	.get_ethtool_stats	= atl1_get_ethtool_stats,
 	.get_sset_count		= atl1_get_sset_count,
-	.set_tso		= ethtool_op_set_tso,
 };
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index 1850a00..0d9b688 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -2107,9 +2107,6 @@ static const struct ethtool_ops atl2_ethtool_ops = {
 	.get_eeprom		= atl2_get_eeprom,
 	.set_eeprom		= atl2_set_eeprom,
 	.get_tx_csum		= atl2_get_tx_csum,
-#ifdef NETIF_F_TSO
-	.get_tso		= ethtool_op_get_tso,
-#endif
 };
 
 static void atl2_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 169429c..8c1eaee 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -698,8 +698,6 @@ const struct ethtool_ops be_ethtool_ops = {
 	.set_rx_csum = be_set_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_hw_csum,
-	.get_tso = ethtool_op_get_tso,
-	.set_tso = ethtool_op_set_tso,
 	.get_strings = be_get_stat_strings,
 	.phys_id = be_phys_id,
 	.get_sset_count = be_get_sset_count,
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index dfa231d..b8a164f 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -2554,7 +2554,7 @@ static void be_netdev_init(struct net_device *netdev)
 
 	BE_SET_NETDEV_OPS(netdev, &be_netdev_ops);
 
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
 
 	for_all_rx_queues(adapter, rxo, i)
diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c
index 207f57b..f8bdebf 100644
--- a/drivers/net/bna/bnad_ethtool.c
+++ b/drivers/net/bna/bnad_ethtool.c
@@ -848,23 +848,6 @@ bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum)
 	return 0;
 }
 
-static int
-bnad_set_tso(struct net_device *netdev, u32 tso)
-{
-	struct bnad *bnad = netdev_priv(netdev);
-
-	mutex_lock(&bnad->conf_mutex);
-	if (tso) {
-		netdev->features |= NETIF_F_TSO;
-		netdev->features |= NETIF_F_TSO6;
-	} else {
-		netdev->features &= ~NETIF_F_TSO;
-		netdev->features &= ~NETIF_F_TSO6;
-	}
-	mutex_unlock(&bnad->conf_mutex);
-	return 0;
-}
-
 static void
 bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
 {
@@ -1261,8 +1244,6 @@ static struct ethtool_ops bnad_ethtool_ops = {
 	.set_rx_csum = bnad_set_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = bnad_set_tx_csum,
-	.get_tso = ethtool_op_get_tso,
-	.set_tso = bnad_set_tso,
 	.get_strings = bnad_get_strings,
 	.get_ethtool_stats = bnad_get_ethtool_stats,
 	.get_sset_count = bnad_get_sset_count
@@ -1272,5 +1253,6 @@ void
 bnad_set_ethtool_ops(struct net_device *netdev)
 {
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
 }
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 50bdafb..8a63a8b 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -7181,21 +7181,6 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static int
-bnx2_set_tso(struct net_device *dev, u32 data)
-{
-	struct bnx2 *bp = netdev_priv(dev);
-
-	if (data) {
-		dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-		if (CHIP_NUM(bp) == CHIP_NUM_5709)
-			dev->features |= NETIF_F_TSO6;
-	} else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
-				   NETIF_F_TSO_ECN);
-	return 0;
-}
-
 static struct {
 	char string[ETH_GSTRING_LEN];
 } bnx2_stats_str_arr[] = {
@@ -7569,7 +7554,6 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
 	.get_rx_csum		= bnx2_get_rx_csum,
 	.set_rx_csum		= bnx2_set_rx_csum,
 	.set_tx_csum		= bnx2_set_tx_csum,
-	.set_tso		= bnx2_set_tso,
 	.self_test		= bnx2_self_test,
 	.get_strings		= bnx2_get_strings,
 	.phys_id		= bnx2_phys_id,
@@ -8320,6 +8304,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	dev->netdev_ops = &bnx2_netdev_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_TSO|NETIF_F_TSO_ECN;
 	dev->ethtool_ops = &bnx2_ethtool_ops;
 
 	bp = netdev_priv(dev);
@@ -8344,6 +8329,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
 	vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
 	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		dev->hw_features |= NETIF_F_TSO6;
 		dev->features |= NETIF_F_TSO6;
 		vlan_features_add(dev, NETIF_F_TSO6);
 	}
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
index 54955fb..3d08714 100644
--- a/drivers/net/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -1183,19 +1183,6 @@ static int bnx2x_set_rx_csum(struct net_device *dev, u32 data)
 	return rc;
 }
 
-static int bnx2x_set_tso(struct net_device *dev, u32 data)
-{
-	if (data) {
-		dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
-		dev->features |= NETIF_F_TSO6;
-	} else {
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
-		dev->features &= ~NETIF_F_TSO6;
-	}
-
-	return 0;
-}
-
 static const struct {
 	char string[ETH_GSTRING_LEN];
 } bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = {
@@ -2082,8 +2069,6 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
 	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
 	.set_flags		= bnx2x_set_flags,
 	.get_flags		= ethtool_op_get_flags,
-	.get_tso		= ethtool_op_get_tso,
-	.set_tso		= bnx2x_set_tso,
 	.self_test		= bnx2x_self_test,
 	.get_sset_count		= bnx2x_get_sset_count,
 	.get_strings		= bnx2x_get_strings,
@@ -2094,5 +2079,6 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
 void bnx2x_set_ethtool_ops(struct net_device *netdev)
 {
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO_ECN|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &bnx2x_ethtool_ops);
 }
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 577b462..4e030c5 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4651,7 +4651,6 @@ static const struct ethtool_ops bond_ethtool_ops = {
 	.get_drvinfo		= bond_ethtool_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_tso		= ethtool_op_get_tso,
 	.get_ufo		= ethtool_op_get_ufo,
 	.get_flags		= ethtool_op_get_flags,
 };
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 7f63ede..712c413 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -723,15 +723,6 @@ static int set_rx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static int set_tso(struct net_device *dev, u32 value)
-{
-	struct adapter *adapter = dev->ml_priv;
-
-	if (!(adapter->flags & TSO_CAPABLE))
-		return value ? -EOPNOTSUPP : 0;
-	return ethtool_op_set_tso(dev, value);
-}
-
 static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 {
 	struct adapter *adapter = dev->ml_priv;
@@ -840,7 +831,6 @@ static const struct ethtool_ops t1_ethtool_ops = {
 	.get_ethtool_stats = get_stats,
 	.get_regs_len      = get_regs_len,
 	.get_regs          = get_regs,
-	.set_tso           = set_tso,
 };
 
 static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
@@ -1131,6 +1121,8 @@ static int __devinit init_one(struct pci_dev *pdev,
 		netif_napi_add(netdev, &adapter->napi, t1_poll, 64);
 
 		netdev->hw_features |= NETIF_F_SG;
+		if (adapter->flags & TSO_CAPABLE)
+			netdev->hw_features |= NETIF_F_TSO;
 		SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
 	}
 
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 2bc7529..1d45f7d 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2106,7 +2106,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
 	.get_regs_len = get_regs_len,
 	.get_regs = get_regs,
 	.get_wol = get_wol,
-	.set_tso = ethtool_op_set_tso,
 };
 
 static int in_range(int val, int lo, int hi)
@@ -3310,7 +3309,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 
 		netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 		netdev->netdev_ops = &cxgb_netdev_ops;
-		netdev->hw_features |= NETIF_F_SG;
+		netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
 	}
 
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index ac843a3..700bb37 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -1870,15 +1870,6 @@ static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
 #define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
 
-static int set_tso(struct net_device *dev, u32 value)
-{
-	if (value)
-		dev->features |= TSO_FLAGS;
-	else
-		dev->features &= ~TSO_FLAGS;
-	return 0;
-}
-
 static int set_flags(struct net_device *dev, u32 flags)
 {
 	int err;
@@ -2021,7 +2012,6 @@ static struct ethtool_ops cxgb_ethtool_ops = {
 	.get_regs          = get_regs,
 	.get_wol           = get_wol,
 	.set_wol           = set_wol,
-	.set_tso           = set_tso,
 	.set_flags         = set_flags,
 	.get_rxnfc         = get_rxnfc,
 	.get_rxfh_indir    = get_rss_table,
@@ -3673,7 +3663,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 		netdev->vlan_features = netdev->features & VLAN_FEAT;
 
 		netdev->netdev_ops = &cxgb4_netdev_ops;
-		netdev->hw_features |= NETIF_F_SG;
+		netdev->hw_features |= NETIF_F_SG | TSO_FLAGS;
 		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
 	}
 
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index ddaba63..61cc28c 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -1539,18 +1539,6 @@ static void cxgb4vf_get_wol(struct net_device *dev,
 	memset(&wol->sopass, 0, sizeof(wol->sopass));
 }
 
-/*
- * Set TCP Segmentation Offloading feature capabilities.
- */
-static int cxgb4vf_set_tso(struct net_device *dev, u32 tso)
-{
-	if (tso)
-		dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
-	else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-	return 0;
-}
-
 static struct ethtool_ops cxgb4vf_ethtool_ops = {
 	.get_settings		= cxgb4vf_get_settings,
 	.get_drvinfo		= cxgb4vf_get_drvinfo,
@@ -1572,7 +1560,6 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = {
 	.get_regs_len		= cxgb4vf_get_regs_len,
 	.get_regs		= cxgb4vf_get_regs,
 	.get_wol		= cxgb4vf_get_wol,
-	.set_tso		= cxgb4vf_set_tso,
 };
 
 /*
@@ -2630,6 +2617,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
 #endif
 #endif
 		netdev->hw_features |= NETIF_F_SG;
+		netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 		SET_ETHTOOL_OPS(netdev, &cxgb4vf_ethtool_ops);
 
 		/*
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index a881dd0..8f14520 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -299,7 +299,6 @@ struct e1000_adapter {
 	int msg_enable;
 
 	/* to not mess up cache alignment, always add to the bottom */
-	bool tso_force;
 	bool smart_power_down;	/* phy smart power down */
 	bool quad_port_a;
 	unsigned long flags;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 008632c..fcde1b2 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -330,27 +330,6 @@ static int e1000_set_tx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static int e1000_set_tso(struct net_device *netdev, u32 data)
-{
-	struct e1000_adapter *adapter = netdev_priv(netdev);
-	struct e1000_hw *hw = &adapter->hw;
-
-	if ((hw->mac_type < e1000_82544) ||
-	    (hw->mac_type == e1000_82547))
-		return data ? -EINVAL : 0;
-
-	if (data)
-		netdev->features |= NETIF_F_TSO;
-	else
-		netdev->features &= ~NETIF_F_TSO;
-
-	netdev->features &= ~NETIF_F_TSO6;
-
-	e_info(probe, "TSO is %s\n", data ? "Enabled" : "Disabled");
-	adapter->tso_force = true;
-	return 0;
-}
-
 static u32 e1000_get_msglevel(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1925,7 +1904,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 	.set_rx_csum            = e1000_set_rx_csum,
 	.get_tx_csum            = e1000_get_tx_csum,
 	.set_tx_csum            = e1000_set_tx_csum,
-	.set_tso                = e1000_set_tso,
 	.self_test              = e1000_diag_test,
 	.get_strings            = e1000_get_strings,
 	.phys_id                = e1000_phys_id,
@@ -1937,6 +1915,12 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 
 void e1000_set_ethtool_ops(struct net_device *netdev)
 {
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
 	netdev->hw_features |= NETIF_F_SG;
+	if (!(adapter->hw.mac_type < e1000_82544) &&
+	    !(adapter->hw.mac_type == e1000_82547))
+		netdev->hw_features |= NETIF_F_TSO;
+
 	SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
 }
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index bb0bcfa..579ed4b 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -406,14 +406,6 @@ static int e1000_set_tso(struct net_device *netdev, u32 data)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 
-	if (data) {
-		netdev->features |= NETIF_F_TSO;
-		netdev->features |= NETIF_F_TSO6;
-	} else {
-		netdev->features &= ~NETIF_F_TSO;
-		netdev->features &= ~NETIF_F_TSO6;
-	}
-
 	adapter->flags |= FLAG_TSO_FORCE;
 	return 0;
 }
@@ -2036,8 +2028,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 	.set_rx_csum		= e1000_set_rx_csum,
 	.get_tx_csum		= e1000_get_tx_csum,
 	.set_tx_csum		= e1000_set_tx_csum,
-	.get_tso		= ethtool_op_get_tso,
-	.set_tso		= e1000_set_tso,
+	.hw_set_tso		= e1000_set_tso,
 	.self_test		= e1000_diag_test,
 	.get_strings		= e1000_get_strings,
 	.phys_id		= e1000_phys_id,
@@ -2051,5 +2042,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 void e1000e_set_ethtool_ops(struct net_device *netdev)
 {
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
 }
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index 75b099c..fb5b9ba 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -267,7 +267,6 @@ const struct ethtool_ops ehea_ethtool_ops = {
 	.get_msglevel = ehea_get_msglevel,
 	.set_msglevel = ehea_set_msglevel,
 	.get_link = ethtool_op_get_link,
-	.set_tso = ethtool_op_set_tso,
 	.get_strings = ehea_get_strings,
 	.get_sset_count = ehea_get_sset_count,
 	.get_ethtool_stats = ehea_get_ethtool_stats,
@@ -278,5 +277,6 @@ const struct ethtool_ops ehea_ethtool_ops = {
 
 void ehea_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &ehea_ethtool_ops);
 }
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index b744fca..88e4a99 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -312,13 +312,6 @@ static int enic_set_tso(struct net_device *netdev, u32 data)
 	if (data && !ENIC_SETTING(enic, TSO))
 		return -EINVAL;
 
-	if (data)
-		netdev->features |=
-			NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN;
-	else
-		netdev->features &=
-			~(NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN);
-
 	return 0;
 }
 
@@ -413,8 +406,7 @@ static const struct ethtool_ops enic_ethtool_ops = {
 	.set_rx_csum = enic_set_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = enic_set_tx_csum,
-	.get_tso = ethtool_op_get_tso,
-	.set_tso = enic_set_tso,
+	.hw_set_tso = enic_set_tso,
 	.get_coalesce = enic_get_coalesce,
 	.set_coalesce = enic_set_coalesce,
 	.get_flags = ethtool_op_get_flags,
@@ -2637,6 +2629,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
 
 	netdev->watchdog_timeo = 2 * HZ;
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6|NETIF_F_TSO_ECN;
 	netdev->ethtool_ops = &enic_ethtool_ops;
 
 	netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index fb8c7c9..8aabb6a 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -4396,16 +4396,6 @@ static int nv_nway_reset(struct net_device *dev)
 	return ret;
 }
 
-static int nv_set_tso(struct net_device *dev, u32 value)
-{
-	struct fe_priv *np = netdev_priv(dev);
-
-	if ((np->driver_data & DEV_HAS_CHECKSUM))
-		return ethtool_op_set_tso(dev, value);
-	else
-		return -EOPNOTSUPP;
-}
-
 static void nv_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
 {
 	struct fe_priv *np = netdev_priv(dev);
@@ -5029,7 +5019,6 @@ static const struct ethtool_ops ops = {
 	.get_regs_len = nv_get_regs_len,
 	.get_regs = nv_get_regs,
 	.nway_reset = nv_nway_reset,
-	.set_tso = nv_set_tso,
 	.get_ringparam = nv_get_ringparam,
 	.set_ringparam = nv_set_ringparam,
 	.get_pauseparam = nv_get_pauseparam,
@@ -5565,7 +5554,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 
 	netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP);
 	if (np->driver_data & DEV_HAS_CHECKSUM)
-		dev->hw_features |= NETIF_F_SG;
+		dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &ops);
 	dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
 
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index 2909af5..de257e4 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -355,23 +355,6 @@ static int igb_set_tx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static int igb_set_tso(struct net_device *netdev, u32 data)
-{
-	struct igb_adapter *adapter = netdev_priv(netdev);
-
-	if (data) {
-		netdev->features |= NETIF_F_TSO;
-		netdev->features |= NETIF_F_TSO6;
-	} else {
-		netdev->features &= ~NETIF_F_TSO;
-		netdev->features &= ~NETIF_F_TSO6;
-	}
-
-	dev_info(&adapter->pdev->dev, "TSO is %s\n",
-		 data ? "Enabled" : "Disabled");
-	return 0;
-}
-
 static u32 igb_get_msglevel(struct net_device *netdev)
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
@@ -2193,8 +2176,6 @@ static const struct ethtool_ops igb_ethtool_ops = {
 	.set_rx_csum            = igb_set_rx_csum,
 	.get_tx_csum            = igb_get_tx_csum,
 	.set_tx_csum            = igb_set_tx_csum,
-	.get_tso                = ethtool_op_get_tso,
-	.set_tso                = igb_set_tso,
 	.self_test              = igb_diag_test,
 	.get_strings            = igb_get_strings,
 	.phys_id                = igb_phys_id,
@@ -2207,5 +2188,6 @@ static const struct ethtool_ops igb_ethtool_ops = {
 void igb_set_ethtool_ops(struct net_device *netdev)
 {
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &igb_ethtool_ops);
 }
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
index 9bf5ea0..56f77b6 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -165,23 +165,6 @@ static int igbvf_set_tx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static int igbvf_set_tso(struct net_device *netdev, u32 data)
-{
-	struct igbvf_adapter *adapter = netdev_priv(netdev);
-
-	if (data) {
-		netdev->features |= NETIF_F_TSO;
-		netdev->features |= NETIF_F_TSO6;
-	} else {
-		netdev->features &= ~NETIF_F_TSO;
-		netdev->features &= ~NETIF_F_TSO6;
-	}
-
-	dev_info(&adapter->pdev->dev, "TSO is %s\n",
-	         data ? "Enabled" : "Disabled");
-	return 0;
-}
-
 static u32 igbvf_get_msglevel(struct net_device *netdev)
 {
 	struct igbvf_adapter *adapter = netdev_priv(netdev);
@@ -527,8 +510,6 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
 	.set_rx_csum            = igbvf_set_rx_csum,
 	.get_tx_csum		= igbvf_get_tx_csum,
 	.set_tx_csum		= igbvf_set_tx_csum,
-	.get_tso		= ethtool_op_get_tso,
-	.set_tso		= igbvf_set_tso,
 	.self_test		= igbvf_diag_test,
 	.get_sset_count		= igbvf_get_sset_count,
 	.get_strings		= igbvf_get_strings,
@@ -541,6 +522,7 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
 void igbvf_set_ethtool_ops(struct net_device *netdev)
 {
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	/* have to "undeclare" const on this struct to remove warnings */
 	SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&igbvf_ethtool_ops);
 }
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 9623e87..b8b38ef 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -234,16 +234,6 @@ ixgb_set_tx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static int
-ixgb_set_tso(struct net_device *netdev, u32 data)
-{
-	if (data)
-		netdev->features |= NETIF_F_TSO;
-	else
-		netdev->features &= ~NETIF_F_TSO;
-	return 0;
-}
-
 static u32
 ixgb_get_msglevel(struct net_device *netdev)
 {
@@ -726,7 +716,6 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
 	.set_tx_csum = ixgb_set_tx_csum,
 	.get_msglevel = ixgb_get_msglevel,
 	.set_msglevel = ixgb_set_msglevel,
-	.set_tso = ixgb_set_tso,
 	.get_strings = ixgb_get_strings,
 	.phys_id = ixgb_phys_id,
 	.get_sset_count = ixgb_get_sset_count,
@@ -735,6 +724,6 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
 
 void ixgb_set_ethtool_ops(struct net_device *netdev)
 {
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &ixgb_ethtool_ops);
 }
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 5f1e17c..561a74d 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -442,18 +442,6 @@ static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static int ixgbe_set_tso(struct net_device *netdev, u32 data)
-{
-	if (data) {
-		netdev->features |= NETIF_F_TSO;
-		netdev->features |= NETIF_F_TSO6;
-	} else {
-		netdev->features &= ~NETIF_F_TSO;
-		netdev->features &= ~NETIF_F_TSO6;
-	}
-	return 0;
-}
-
 static u32 ixgbe_get_msglevel(struct net_device *netdev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -2289,8 +2277,6 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
 	.set_tx_csum            = ixgbe_set_tx_csum,
 	.get_msglevel           = ixgbe_get_msglevel,
 	.set_msglevel           = ixgbe_set_msglevel,
-	.get_tso                = ethtool_op_get_tso,
-	.set_tso                = ixgbe_set_tso,
 	.self_test              = ixgbe_diag_test,
 	.get_strings            = ixgbe_get_strings,
 	.phys_id                = ixgbe_phys_id,
@@ -2306,5 +2292,6 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
 void ixgbe_set_ethtool_ops(struct net_device *netdev)
 {
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops);
 }
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
index 624375a..58ae092 100644
--- a/drivers/net/ixgbevf/ethtool.c
+++ b/drivers/net/ixgbevf/ethtool.c
@@ -139,20 +139,6 @@ static int ixgbevf_set_rx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static int ixgbevf_set_tso(struct net_device *netdev, u32 data)
-{
-	if (data) {
-		netdev->features |= NETIF_F_TSO;
-		netdev->features |= NETIF_F_TSO6;
-	} else {
-		netif_tx_stop_all_queues(netdev);
-		netdev->features &= ~NETIF_F_TSO;
-		netdev->features &= ~NETIF_F_TSO6;
-		netif_tx_start_all_queues(netdev);
-	}
-	return 0;
-}
-
 static u32 ixgbevf_get_msglevel(struct net_device *netdev)
 {
 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
@@ -720,8 +706,6 @@ static struct ethtool_ops ixgbevf_ethtool_ops = {
 	.set_tx_csum            = ethtool_op_set_tx_ipv6_csum,
 	.get_msglevel           = ixgbevf_get_msglevel,
 	.set_msglevel           = ixgbevf_set_msglevel,
-	.get_tso                = ethtool_op_get_tso,
-	.set_tso                = ixgbevf_set_tso,
 	.self_test              = ixgbevf_diag_test,
 	.get_sset_count         = ixgbevf_get_sset_count,
 	.get_strings            = ixgbevf_get_strings,
@@ -731,5 +715,6 @@ static struct ethtool_ops ixgbevf_ethtool_ops = {
 void ixgbevf_set_ethtool_ops(struct net_device *netdev)
 {
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &ixgbevf_ethtool_ops);
 }
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 1f7a0a7..f837c3f 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -2530,11 +2530,10 @@ jme_set_tso(struct net_device *netdev, u32 on)
 
 	if (on) {
 		set_bit(JME_FLAG_TSO, &jme->flags);
-		if (netdev->mtu <= 1900)
-			netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+		if (netdev->mtu > 1900)
+			return 1;
 	} else {
 		clear_bit(JME_FLAG_TSO, &jme->flags);
-		netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
 	}
 
 	return 0;
@@ -2684,7 +2683,7 @@ static const struct ethtool_ops jme_ethtool_ops = {
 	.get_rx_csum		= jme_get_rx_csum,
 	.set_rx_csum		= jme_set_rx_csum,
 	.set_tx_csum		= jme_set_tx_csum,
-	.set_tso		= jme_set_tso,
+	.hw_set_tso		= jme_set_tso,
 	.nway_reset             = jme_nway_reset,
 	.get_eeprom_len		= jme_get_eeprom_len,
 	.get_eeprom		= jme_get_eeprom,
@@ -2794,7 +2793,7 @@ jme_init_one(struct pci_dev *pdev,
 		goto err_out_release_regions;
 	}
 	netdev->netdev_ops = &jme_netdev_ops;
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6;
 	netdev->ethtool_ops		= &jme_ethtool_ops;
 	netdev->watchdog_timeo		= TX_TIMEOUT;
 	netdev->features		=	NETIF_F_HW_CSUM |
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 208e9f4..76e900c 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -129,7 +129,6 @@ static u32 always_on(struct net_device *dev)
 
 static const struct ethtool_ops loopback_ethtool_ops = {
 	.get_link		= always_on,
-	.set_tso		= ethtool_op_set_tso,
 	.get_tx_csum		= always_on,
 	.get_rx_csum		= always_on,
 };
@@ -174,6 +173,7 @@ static void loopback_setup(struct net_device *dev)
 		| NETIF_F_HIGHDMA
 		| NETIF_F_LLTX
 		| NETIF_F_NETNS_LOCAL;
+	dev->hw_features |= NETIF_F_TSO;
 	dev->ethtool_ops	= &loopback_ethtool_ops;
 	dev->header_ops		= &eth_header_ops;
 	dev->netdev_ops		= &loopback_ops;
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index 1b355b7..a963bcd 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -57,21 +57,13 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 	drvinfo->eedump_len = 0;
 }
 
-static u32 mlx4_en_get_tso(struct net_device *dev)
-{
-	return (dev->features & NETIF_F_TSO) != 0;
-}
-
 static int mlx4_en_set_tso(struct net_device *dev, u32 data)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 
-	if (data) {
-		if (!priv->mdev->LSO_support)
-			return -EPERM;
-		dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
-	} else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+	if (data && !priv->mdev->LSO_support)
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -426,10 +418,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
 	.get_drvinfo = mlx4_en_get_drvinfo,
 	.get_settings = mlx4_en_get_settings,
 	.set_settings = mlx4_en_set_settings,
-#ifdef NETIF_F_TSO
-	.get_tso = mlx4_en_get_tso,
-	.set_tso = mlx4_en_set_tso,
-#endif
+	.hw_set_tso = mlx4_en_set_tso,
 	.get_link = ethtool_op_get_link,
 	.get_rx_csum = mlx4_en_get_rx_csum,
 	.set_rx_csum = mlx4_en_set_rx_csum,
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index f496dbc..b867b34 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -1039,6 +1039,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
 
 	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
 
 	/* Set defualt MAC */
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 3696bba..4f8b838 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1773,18 +1773,6 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
 	return err;
 }
 
-static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
-{
-	struct myri10ge_priv *mgp = netdev_priv(netdev);
-	unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO);
-
-	if (tso_enabled)
-		netdev->features |= flags;
-	else
-		netdev->features &= ~flags;
-	return 0;
-}
-
 static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = {
 	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
 	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -1951,7 +1939,6 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
 	.get_rx_csum = myri10ge_get_rx_csum,
 	.set_rx_csum = myri10ge_set_rx_csum,
 	.set_tx_csum = ethtool_op_set_tx_hw_csum,
-	.set_tso = myri10ge_set_tso,
 	.get_link = ethtool_op_get_link,
 	.get_strings = myri10ge_get_strings,
 	.get_sset_count = myri10ge_get_sset_count,
@@ -3998,6 +3985,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	spin_lock_init(&mgp->stats_lock);
 	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops);
 	INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog);
 	status = register_netdev(netdev);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index f22f0a7..9244bb1 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -724,30 +724,6 @@ static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static u32 netxen_nic_get_tso(struct net_device *dev)
-{
-	struct netxen_adapter *adapter = netdev_priv(dev);
-
-	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
-		return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
-
-	return (dev->features & NETIF_F_TSO) != 0;
-}
-
-static int netxen_nic_set_tso(struct net_device *dev, u32 data)
-{
-	if (data) {
-		struct netxen_adapter *adapter = netdev_priv(dev);
-
-		dev->features |= NETIF_F_TSO;
-		if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
-			dev->features |= NETIF_F_TSO6;
-	} else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
-	return 0;
-}
-
 static void
 netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
@@ -926,8 +902,6 @@ const struct ethtool_ops netxen_nic_ethtool_ops = {
 	.set_pauseparam = netxen_nic_set_pauseparam,
 	.get_tx_csum = netxen_nic_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_csum,
-	.get_tso = netxen_nic_get_tso,
-	.set_tso = netxen_nic_set_tso,
 	.get_wol = netxen_nic_get_wol,
 	.set_wol = netxen_nic_set_wol,
 	.self_test = netxen_nic_diag_test,
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 4b2874c..573e51f 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -1210,7 +1210,9 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
 
 	netxen_nic_change_mtu(netdev, netdev->mtu);
 
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
+	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+		netdev->hw_features |= NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
 
 	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index ceba22d..abf89ba 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -931,24 +931,6 @@ static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static u32 qlcnic_get_tso(struct net_device *dev)
-{
-	return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
-}
-
-static int qlcnic_set_tso(struct net_device *dev, u32 data)
-{
-	struct qlcnic_adapter *adapter = netdev_priv(dev);
-	if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO))
-		return -EOPNOTSUPP;
-	if (data)
-		dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
-	else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
-	return 0;
-}
-
 static int qlcnic_blink_led(struct net_device *dev, u32 val)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
@@ -1166,8 +1148,6 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
 	.set_pauseparam = qlcnic_set_pauseparam,
 	.get_tx_csum = qlcnic_get_tx_csum,
 	.set_tx_csum = qlcnic_set_tx_csum,
-	.get_tso = qlcnic_get_tso,
-	.set_tso = qlcnic_set_tso,
 	.get_wol = qlcnic_get_wol,
 	.set_wol = qlcnic_set_wol,
 	.self_test = qlcnic_diag_test,
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 30ed19a..53e07ed 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -1434,6 +1434,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
 		NETIF_F_IPV6_CSUM);
 
 	if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+		netdev->hw_features |= (NETIF_F_TSO | NETIF_F_TSO6);
 		netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
 		netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
 	}
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index d8b2d3f..9b7bddf 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -655,19 +655,6 @@ static int ql_set_rx_csum(struct net_device *netdev, uint32_t data)
 	return 0;
 }
 
-static int ql_set_tso(struct net_device *ndev, uint32_t data)
-{
-
-	if (data) {
-		ndev->features |= NETIF_F_TSO;
-		ndev->features |= NETIF_F_TSO6;
-	} else {
-		ndev->features &= ~NETIF_F_TSO;
-		ndev->features &= ~NETIF_F_TSO6;
-	}
-	return 0;
-}
-
 static u32 ql_get_msglevel(struct net_device *ndev)
 {
 	struct ql_adapter *qdev = netdev_priv(ndev);
@@ -698,8 +685,6 @@ const struct ethtool_ops qlge_ethtool_ops = {
 	.set_rx_csum = ql_set_rx_csum,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_csum,
-	.get_tso = ethtool_op_get_tso,
-	.set_tso = ql_set_tso,
 	.get_coalesce = ql_get_coalesce,
 	.set_coalesce = ql_set_coalesce,
 	.get_sset_count = ql_get_sset_count,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 75b708c..fb36da6 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -4714,6 +4714,7 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
 
 	ndev->netdev_ops = &qlge_netdev_ops;
 	ndev->hw_features |= NETIF_F_SG;
+	ndev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops);
 	ndev->watchdog_timeo = 10 * HZ;
 
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 746e296..999a713 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1277,7 +1277,6 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
 	.get_rx_csum		= rtl8169_get_rx_csum,
 	.set_rx_csum		= rtl8169_set_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
-	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= rtl8169_get_regs,
 	.get_wol		= rtl8169_get_wol,
 	.set_wol		= rtl8169_set_wol,
@@ -3172,7 +3171,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
 	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
 	dev->irq = pdev->irq;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index e447a4d..ef63529 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -6704,21 +6704,6 @@ static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
-{
-	return (dev->features & NETIF_F_TSO) != 0;
-}
-
-static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
-	else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
-	return 0;
-}
-
 static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
 {
 	struct s2io_nic *sp = netdev_priv(dev);
@@ -6769,8 +6754,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
 	.set_tx_csum = s2io_ethtool_op_set_tx_csum,
 	.set_flags = s2io_ethtool_set_flags,
 	.get_flags = ethtool_op_get_flags,
-	.get_tso = s2io_ethtool_op_get_tso,
-	.set_tso = s2io_ethtool_op_set_tso,
 	.set_ufo = ethtool_op_set_ufo,
 	.self_test = s2io_ethtool_test,
 	.get_strings = s2io_ethtool_get_strings,
@@ -8034,6 +8017,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 	/*  Driver entry points */
 	dev->netdev_ops = &s2io_netdev_ops;
 	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 	dev->features |= NETIF_F_LRO;
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index b6b0f5d..26bb98b 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1882,7 +1882,9 @@ static int efx_register_netdev(struct efx_nic *efx)
 	net_dev->watchdog_timeo = 5 * HZ;
 	net_dev->irq = efx->pci_dev->irq;
 	net_dev->netdev_ops = &efx_netdev_ops;
-	net_dev->hw_features |= NETIF_F_SG;
+	net_dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
+	if (efx->type->offload_features & NETIF_F_V6_CSUM)
+		net_dev->hw_features |= NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
 
 	/* Clear MAC statistics */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index c994666..dd2b271 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -500,23 +500,6 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
 	}
 }
 
-static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
-{
-	struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev);
-	unsigned long features;
-
-	features = NETIF_F_TSO;
-	if (efx->type->offload_features & NETIF_F_V6_CSUM)
-		features |= NETIF_F_TSO6;
-
-	if (enable)
-		net_dev->features |= features;
-	else
-		net_dev->features &= ~features;
-
-	return 0;
-}
-
 static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
@@ -1130,9 +1113,6 @@ const struct ethtool_ops efx_ethtool_ops = {
 	.get_tx_csum		= ethtool_op_get_tx_csum,
 	/* Need to enable/disable IPv6 too */
 	.set_tx_csum		= efx_ethtool_set_tx_csum,
-	.get_tso		= ethtool_op_get_tso,
-	/* Need to enable/disable TSO-IPv6 too */
-	.set_tso		= efx_ethtool_set_tso,
 	.get_flags		= ethtool_op_get_flags,
 	.set_flags		= efx_ethtool_set_flags,
 	.get_sset_count		= efx_ethtool_get_sset_count,
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index a06bb6e..98534ef 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -4080,7 +4080,7 @@ static int sky2_set_tso(struct net_device *dev, u32 data)
 	if (data && no_tx_offload(dev))
 		return -EINVAL;
 
-	return ethtool_op_set_tso(dev, data);
+	return 0;
 }
 
 static int sky2_get_eeprom_len(struct net_device *dev)
@@ -4217,7 +4217,7 @@ static const struct ethtool_ops sky2_ethtool_ops = {
 	.get_eeprom	= sky2_get_eeprom,
 	.set_eeprom	= sky2_set_eeprom,
 	.set_tx_csum	= sky2_set_tx_csum,
-	.set_tso	= sky2_set_tso,
+	.hw_set_tso	= sky2_set_tso,
 	.get_rx_csum	= sky2_get_rx_csum,
 	.set_rx_csum	= sky2_set_rx_csum,
 	.get_strings	= sky2_get_strings,
@@ -4549,7 +4549,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
 
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->irq = hw->pdev->irq;
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops);
 	dev->watchdog_timeo = TX_WATCHDOG;
 	dev->netdev_ops = &sky2_netdev_ops[port];
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
index 4461a9e..0674ebb 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -378,12 +378,10 @@ static struct ethtool_ops stmmac_ethtool_ops = {
 	.get_wol = stmmac_get_wol,
 	.set_wol = stmmac_set_wol,
 	.get_sset_count	= stmmac_get_sset_count,
-	.get_tso = ethtool_op_get_tso,
-	.set_tso = ethtool_op_set_tso,
 };
 
 void stmmac_set_ethtool_ops(struct net_device *netdev)
 {
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops);
 }
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index ed6dc44..42913bf 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -2426,7 +2426,6 @@ static void bdx_set_ethtool_ops(struct net_device *netdev)
 		.set_ringparam = bdx_set_ringparam,
 		.get_rx_csum = bdx_get_rx_csum,
 		.get_tx_csum = bdx_get_tx_csum,
-		.get_tso = ethtool_op_get_tso,
 		.get_strings = bdx_get_strings,
 		.get_sset_count = bdx_get_sset_count,
 		.get_ethtool_stats = bdx_get_ethtool_stats,
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index b07e2d1..c08172d 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -6142,7 +6142,7 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
 	if (new_mtu > ETH_DATA_LEN) {
 		if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
 			tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
-			ethtool_op_set_tso(dev, 0);
+			dev->features &= ~NETIF_F_ALL_TSO;
 		} else {
 			tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE;
 		}
@@ -9977,27 +9977,28 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
 {
 	struct tg3 *tp = netdev_priv(dev);
 
-	if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
-		if (value)
-			return -EINVAL;
+	if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && value)
+		return -EINVAL;
+
+	if (!value)
 		return 0;
-	}
+
+	dev->features |= NETIF_F_TSO;
+
 	if ((dev->features & NETIF_F_IPV6_CSUM) &&
 	    ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) ||
 	     (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3))) {
-		if (value) {
-			dev->features |= NETIF_F_TSO6;
-			if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) ||
-			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-			    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
-			     GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
-			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
-			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
-				dev->features |= NETIF_F_TSO_ECN;
-		} else
-			dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
+		dev->features |= NETIF_F_TSO6;
+		if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+		    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+		     GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+			dev->features |= NETIF_F_TSO_ECN;
 	}
-	return ethtool_op_set_tso(dev, value);
+
+	return 1;
 }
 
 static int tg3_nway_reset(struct net_device *dev)
@@ -11306,7 +11307,7 @@ static const struct ethtool_ops tg3_ethtool_ops = {
 	.get_rx_csum		= tg3_get_rx_csum,
 	.set_rx_csum		= tg3_set_rx_csum,
 	.set_tx_csum		= tg3_set_tx_csum,
-	.set_tso		= tg3_set_tso,
+	.hw_set_tso		= tg3_set_tso,
 	.self_test		= tg3_self_test,
 	.get_strings		= tg3_get_strings,
 	.phys_id		= tg3_phys_id,
@@ -14681,6 +14682,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 	tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
 
 	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6|NETIF_F_TSO_ECN;
 	dev->ethtool_ops = &tg3_ethtool_ops;
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
 	dev->irq = pdev->irq;
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 4b49dd7..cc2f811 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1191,7 +1191,6 @@ static const struct ethtool_ops typhoon_ethtool_ops = {
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= typhoon_get_rx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
-	.set_tso		= ethtool_op_set_tso,
 	.get_ringparam		= typhoon_get_ringparam,
 	.set_flags		= typhoon_set_flags,
 	.get_flags		= ethtool_op_get_flags,
@@ -2479,7 +2478,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
 	dev->watchdog_timeo	= TX_TIMEOUT;
 
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &typhoon_ethtool_ops);
 
 	/* We can handle scatter gather, up to 16 entries, and
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 753ee6e..466ed50 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -617,16 +617,6 @@ static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
 	return smsc75xx_set_rx_csum_offload(dev);
 }
 
-static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data)
-{
-	if (data)
-		netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
-	else
-		netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
-	return 0;
-}
-
 static const struct ethtool_ops smsc75xx_ethtool_ops = {
 	.get_link	= usbnet_get_link,
 	.nway_reset	= usbnet_nway_reset,
@@ -642,8 +632,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = {
 	.set_tx_csum	= ethtool_op_set_tx_hw_csum,
 	.get_rx_csum	= smsc75xx_ethtool_get_rx_csum,
 	.set_rx_csum	= smsc75xx_ethtool_set_rx_csum,
-	.get_tso	= ethtool_op_get_tso,
-	.set_tso	= smsc75xx_ethtool_set_tso,
 };
 
 static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -964,8 +952,6 @@ static int smsc75xx_reset(struct usbnet *dev)
 	ret = smsc75xx_set_rx_csum_offload(dev);
 	check_warn_return(ret, "Failed to set rx csum offload: %d", ret);
 
-	smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE);
-
 	smsc75xx_set_multicast(dev->net);
 
 	ret = smsc75xx_phy_initialize(dev);
@@ -1069,11 +1055,14 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
 
 	/* We have to advertise SG otherwise TSO cannot be enabled */
 	dev->net->features |= NETIF_F_SG;
+	if (DEFAULT_TSO_ENABLE)
+		dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6;
 
 	/* Init all registers */
 	ret = smsc75xx_reset(dev);
 
 	dev->net->netdev_ops = &smsc75xx_netdev_ops;
+	dev->net->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
 	dev->net->ethtool_ops = &smsc75xx_ethtool_ops;
 	dev->net->flags |= IFF_MULTICAST;
 	dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b332e92..037913f 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -818,7 +818,6 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
 
 static const struct ethtool_ops virtnet_ethtool_ops = {
 	.set_tx_csum = virtnet_set_tx_csum,
-	.set_tso = ethtool_op_set_tso,
 	.set_ufo = ethtool_op_set_ufo,
 	.get_link = ethtool_op_get_link,
 };
@@ -902,7 +901,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 	/* Set up network device as normal. */
 	dev->netdev_ops = &virtnet_netdev;
 	dev->features = NETIF_F_HIGHDMA;
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
 	SET_NETDEV_DEV(dev, &vdev->dev);
 
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 9925d2b..a43c5fb 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -547,8 +547,6 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
 	.set_rx_csum       = vmxnet3_set_rx_csum,
 	.get_tx_csum       = ethtool_op_get_tx_csum,
 	.set_tx_csum       = ethtool_op_set_tx_hw_csum,
-	.get_tso           = ethtool_op_get_tso,
-	.set_tso           = ethtool_op_set_tso,
 	.get_strings       = vmxnet3_get_strings,
 	.get_flags	   = ethtool_op_get_flags,
 	.set_flags	   = vmxnet3_set_flags,
@@ -560,6 +558,6 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
 
 void vmxnet3_set_ethtool_ops(struct net_device *netdev)
 {
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &vmxnet3_ethtool_ops);
 }
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
index 3c7ccd0..df9e500 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/vxge/vxge-ethtool.c
@@ -1090,16 +1090,6 @@ static int vxge_set_rx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static int vxge_ethtool_op_set_tso(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
-	else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
-	return 0;
-}
-
 static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset)
 {
 	struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
@@ -1132,8 +1122,6 @@ static const struct ethtool_ops vxge_ethtool_ops = {
 	.set_rx_csum		= vxge_set_rx_csum,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
-	.get_tso		= ethtool_op_get_tso,
-	.set_tso		= vxge_ethtool_op_set_tso,
 	.get_strings		= vxge_ethtool_get_strings,
 	.phys_id		= vxge_ethtool_idnic,
 	.get_sset_count		= vxge_ethtool_get_sset_count,
@@ -1143,5 +1131,6 @@ static const struct ethtool_ops vxge_ethtool_ops = {
 void vxge_initialize_ethtool_ops(struct net_device *ndev)
 {
 	ndev->hw_features |= NETIF_F_SG;
+	ndev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(ndev, &vxge_ethtool_ops);
 }
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index e494cc2..5715ba6 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1178,7 +1178,7 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev
 	netif_napi_add(netdev, &np->napi, xennet_poll, 64);
 	netdev->features        = NETIF_F_IP_CSUM;
 
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
 	SET_NETDEV_DEV(netdev, &dev->dev);
 
@@ -1508,7 +1508,7 @@ static int xennet_set_tso(struct net_device *dev, u32 data)
 			return -ENOSYS;
 	}
 
-	return ethtool_op_set_tso(dev, data);
+	return 0;
 }
 
 static void xennet_set_features(struct net_device *dev)
@@ -1525,7 +1525,8 @@ static void xennet_set_features(struct net_device *dev)
 
 	if (!xennet_set_sg(dev, 1)) {
 		dev->features |= NETIF_F_SG;
-		xennet_set_tso(dev, 1);
+		if (!xennet_set_tso(dev, 1))
+			dev->features |= NETIF_F_TSO;
 	}
 }
 
@@ -1640,7 +1641,7 @@ static const struct ethtool_ops xennet_ethtool_ops =
 {
 	.set_tx_csum = ethtool_op_set_tx_csum,
 	.hw_set_sg = xennet_set_sg,
-	.set_tso = xennet_set_tso,
+	.hw_set_tso = xennet_set_tso,
 	.get_link = ethtool_op_get_link,
 };
 
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 5fd646f..efd49c9 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3230,7 +3230,7 @@ static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data)
 		dev->features &= ~NETIF_F_TSO;
 		card->options.large_send = QETH_LARGE_SEND_NO;
 	}
-	return rc;
+	return rc ? rc : 1;
 }
 
 static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data)
@@ -3254,8 +3254,7 @@ static const struct ethtool_ops qeth_l3_ethtool_ops = {
 	.set_tx_csum = qeth_l3_ethtool_set_tx_csum,
 	.get_rx_csum = qeth_l3_ethtool_get_rx_csum,
 	.set_rx_csum = qeth_l3_ethtool_set_rx_csum,
-	.get_tso     = ethtool_op_get_tso,
-	.set_tso     = qeth_l3_ethtool_set_tso,
+	.hw_set_tso  = qeth_l3_ethtool_set_tso,
 	.get_strings = qeth_core_get_strings,
 	.get_ethtool_stats = qeth_core_get_ethtool_stats,
 	.get_sset_count = qeth_core_get_sset_count,
@@ -3355,7 +3354,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
 	card->dev->ml_priv = card;
 	card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
 	card->dev->mtu = card->info.initial_mtu;
-	card->dev->hw_features |= NETIF_F_SG;
+	card->dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops);
 	card->dev->features |=	NETIF_F_HW_VLAN_TX |
 				NETIF_F_HW_VLAN_RX |
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 6b26e3e..0efb1c9 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -548,8 +548,6 @@ u32 ethtool_op_get_tx_csum(struct net_device *dev);
 int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
 int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
 int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data);
-u32 ethtool_op_get_tso(struct net_device *dev);
-int ethtool_op_set_tso(struct net_device *dev, u32 data);
 u32 ethtool_op_get_ufo(struct net_device *dev);
 int ethtool_op_set_ufo(struct net_device *dev, u32 data);
 u32 ethtool_op_get_flags(struct net_device *dev);
@@ -581,8 +579,7 @@ void ethtool_ntuple_flush(struct net_device *dev);
  * get_tx_csum: Report whether transmit checksums are turned on or off
  * set_tx_csum: Turn transmit checksums on or off
  * hw_set_sg: Turn scatter-gather on or off
- * get_tso: Report whether TCP segmentation offload is enabled
- * set_tso: Turn TCP segmentation offload on or off
+ * hw_set_tso: Turn TCP segmentation offload on or off
  * get_ufo: Report whether UDP fragmentation offload is enabled
  * set_ufo: Turn UDP fragmentation offload on or off
  * self_test: Run specified self-tests
@@ -646,8 +643,7 @@ struct ethtool_ops {
 	u32	(*get_tx_csum)(struct net_device *);
 	int	(*set_tx_csum)(struct net_device *, u32);
 	int	(*hw_set_sg)(struct net_device *, u32);
-	u32	(*get_tso)(struct net_device *);
-	int	(*set_tso)(struct net_device *, u32);
+	int	(*hw_set_tso)(struct net_device *, u32);
 	void	(*self_test)(struct net_device *, struct ethtool_test *, u64 *);
 	void	(*get_strings)(struct net_device *, u32 stringset, u8 *);
 	int	(*phys_id)(struct net_device *, u32);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f11a5a1..1c35967 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -877,6 +877,8 @@ struct net_device {
 #define NETIF_F_V6_CSUM		(NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
 #define NETIF_F_ALL_CSUM	(NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
 
+#define NETIF_F_ALL_TSO		(NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6)
+
 	/*
 	 * If one device supports one of these features, then enable them
 	 * for all in netdev_increment_features.
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 14e3d1f..fae31b1 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -872,7 +872,7 @@ static int vlan_ethtool_set_tso(struct net_device *dev, u32 data)
 	} else {
 		dev->features &= ~NETIF_F_TSO;
 	}
-	return 0;
+	return 1;
 }
 
 static const struct ethtool_ops vlan_ethtool_ops = {
@@ -881,7 +881,7 @@ static const struct ethtool_ops vlan_ethtool_ops = {
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= vlan_ethtool_get_rx_csum,
 	.get_flags		= vlan_ethtool_get_flags,
-	.set_tso                = vlan_ethtool_set_tso,
+	.hw_set_tso             = vlan_ethtool_set_tso,
 };
 
 static const struct net_device_ops vlan_netdev_ops = {
@@ -992,6 +992,7 @@ void vlan_setup(struct net_device *dev)
 
 	dev->netdev_ops		= &vlan_netdev_ops;
 	dev->destructor		= free_netdev;
+	dev->hw_features	= NETIF_F_ALL_TSO;
 	dev->ethtool_ops	= &vlan_ethtool_ops;
 
 	memset(dev->broadcast, 0, ETH_ALEN);
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 3d12ebc..dbda588 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -196,7 +196,7 @@ static int br_set_tso(struct net_device *dev, u32 data)
 		br->feature_mask &= ~NETIF_F_TSO;
 
 	br_features_recompute(br);
-	return 0;
+	return 1;
 }
 
 static int br_set_tx_csum(struct net_device *dev, u32 data)
@@ -303,8 +303,7 @@ static const struct ethtool_ops br_ethtool_ops = {
 	.get_tx_csum	= ethtool_op_get_tx_csum,
 	.set_tx_csum 	= br_set_tx_csum,
 	.hw_set_sg	= br_set_sg,
-	.get_tso	= ethtool_op_get_tso,
-	.set_tso	= br_set_tso,
+	.hw_set_tso	= br_set_tso,
 	.get_ufo	= ethtool_op_get_ufo,
 	.set_ufo	= ethtool_op_set_ufo,
 	.get_flags	= ethtool_op_get_flags,
@@ -342,7 +341,7 @@ void br_dev_setup(struct net_device *dev)
 
 	dev->netdev_ops = &br_netdev_ops;
 	dev->destructor = br_dev_free;
-	dev->hw_features = NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_ALL_TSO;
 	SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
 	dev->tx_queue_len = 0;
 	dev->priv_flags = IFF_EBRIDGE;
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 017667c..9b0e598 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -78,23 +78,6 @@ int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
 }
 EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
 
-u32 ethtool_op_get_tso(struct net_device *dev)
-{
-	return (dev->features & NETIF_F_TSO) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_tso);
-
-int ethtool_op_set_tso(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= NETIF_F_TSO;
-	else
-		dev->features &= ~NETIF_F_TSO;
-
-	return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tso);
-
 u32 ethtool_op_get_ufo(struct net_device *dev)
 {
 	return (dev->features & NETIF_F_UFO) != 0;
@@ -1065,10 +1048,13 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
 {
 	int err;
 
-	if (!data && dev->ethtool_ops->set_tso) {
-		err = dev->ethtool_ops->set_tso(dev, 0);
-		if (err)
-			return err;
+	if (!data && (dev->hw_features & NETIF_F_ALL_TSO)) {
+		if (dev->ethtool_ops->hw_set_tso) {
+			err = dev->ethtool_ops->hw_set_tso(dev, 0);
+			if (err < 0)
+				return err;
+		}
+		dev->features &= dev->hw_features & NETIF_F_ALL_TSO;
 	}
 
 	if (!data && dev->ethtool_ops->set_ufo) {
@@ -1145,11 +1131,16 @@ static int ethtool_set_sg(struct net_device *dev, char __user *useraddr)
 	return __ethtool_set_sg(dev, edata.data);
 }
 
+static u32 ethtool_get_tso(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_ALL_TSO) != 0;
+}
+
 static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_value edata;
 
-	if (!dev->ethtool_ops->set_tso)
+	if (!(dev->hw_features & NETIF_F_ALL_TSO))
 		return -EOPNOTSUPP;
 
 	if (copy_from_user(&edata, useraddr, sizeof(edata)))
@@ -1158,7 +1149,18 @@ static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
 	if (edata.data && !(dev->features & NETIF_F_SG))
 		return -EINVAL;
 
-	return dev->ethtool_ops->set_tso(dev, edata.data);
+	if (dev->ethtool_ops->hw_set_tso) {
+		int err = dev->ethtool_ops->hw_set_tso(dev, edata.data);
+		if (err)
+			return min(err, 0);
+	}
+
+	if (edata.data)
+		dev->features |= dev->hw_features & NETIF_F_ALL_TSO;
+	else
+		dev->features &= ~NETIF_F_ALL_TSO;
+
+	return 0;
 }
 
 static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
@@ -1582,9 +1584,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 		break;
 	case ETHTOOL_GTSO:
 		rc = ethtool_get_value(dev, useraddr, ethcmd,
-				       (dev->ethtool_ops->get_tso ?
-					dev->ethtool_ops->get_tso :
-					ethtool_op_get_tso));
+					ethtool_get_tso);
 		break;
 	case ETHTOOL_STSO:
 		rc = ethtool_set_tso(dev, useraddr);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 4/4] Ethtool: convert get_tx_csum/set_tx_csum calls to hw_features flags
  2010-10-31  3:40 [PATCH 0/4] Ethtool: cleanup strategy Michał Mirosław
                   ` (2 preceding siblings ...)
  2010-10-30  8:44 ` [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags Michał Mirosław
@ 2010-10-31  0:09 ` Michał Mirosław
  2010-11-01 21:38   ` Ben Hutchings
  2010-10-31  4:18 ` [PATCH 0/4] Ethtool: cleanup strategy David Miller
  2010-11-01 21:05 ` Ben Hutchings
  5 siblings, 1 reply; 22+ messages in thread
From: Michał Mirosław @ 2010-10-31  0:09 UTC (permalink / raw)
  To: netdev
  Cc: e1000-devel, Steve Glendinning, Greg Kroah-Hartman, Rasesh Mody,
	Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers


Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 drivers/infiniband/hw/nes/nes_nic.c     |    3 +-
 drivers/net/8139cp.c                    |    2 +-
 drivers/net/atl1c/atl1c_ethtool.c       |    6 ---
 drivers/net/atl1e/atl1e_ethtool.c       |    2 +-
 drivers/net/atlx/atl1.c                 |    2 +-
 drivers/net/atlx/atl2.c                 |    6 ---
 drivers/net/benet/be_ethtool.c          |    2 -
 drivers/net/benet/be_main.c             |    1 +
 drivers/net/bna/bnad_ethtool.c          |   20 +---------
 drivers/net/bnx2.c                      |   15 +------
 drivers/net/bnx2x/bnx2x_ethtool.c       |    4 +-
 drivers/net/bonding/bond_main.c         |    1 -
 drivers/net/chelsio/cxgb2.c             |    3 +-
 drivers/net/cxgb3/cxgb3_main.c          |    2 +-
 drivers/net/cxgb4/cxgb4_main.c          |    2 +-
 drivers/net/cxgb4vf/cxgb4vf_main.c      |    2 +-
 drivers/net/dm9000.c                    |   17 +-------
 drivers/net/e1000/e1000_ethtool.c       |   28 +------------
 drivers/net/e1000e/ethtool.c            |   19 +---------
 drivers/net/enic/enic_main.c            |    9 +---
 drivers/net/forcedeth.c                 |   13 +------
 drivers/net/fs_enet/fs_enet-main.c      |    3 +-
 drivers/net/gianfar.c                   |    1 +
 drivers/net/gianfar_ethtool.c           |   31 ---------------
 drivers/net/greth.c                     |   16 +-------
 drivers/net/ibm_newemac/core.c          |    1 -
 drivers/net/ibmveth.c                   |    4 +-
 drivers/net/igb/igb_ethtool.c           |   28 ++-----------
 drivers/net/igbvf/ethtool.c             |   17 +--------
 drivers/net/ioc3-eth.c                  |    3 +-
 drivers/net/ixgb/ixgb_ethtool.c         |   20 +---------
 drivers/net/ixgbe/ixgbe_ethtool.c       |   30 +++-----------
 drivers/net/ixgbevf/ethtool.c           |    3 +-
 drivers/net/jme.c                       |    8 ++--
 drivers/net/ksz884x.c                   |    3 +-
 drivers/net/loopback.c                  |    1 -
 drivers/net/mlx4/en_ethtool.c           |    2 -
 drivers/net/mlx4/en_netdev.c            |    1 +
 drivers/net/mv643xx_eth.c               |    3 +-
 drivers/net/myri10ge/myri10ge.c         |    3 +-
 drivers/net/netxen/netxen_nic_ethtool.c |    7 ---
 drivers/net/netxen/netxen_nic_main.c    |    1 +
 drivers/net/pch_gbe/pch_gbe_ethtool.c   |   20 +---------
 drivers/net/ps3_gelic_net.c             |    3 +-
 drivers/net/ps3_gelic_wireless.c        |    3 +-
 drivers/net/qlcnic/qlcnic_ethtool.c     |   21 ----------
 drivers/net/qlcnic/qlcnic_main.c        |    2 +
 drivers/net/qlge/qlge_ethtool.c         |    2 -
 drivers/net/qlge/qlge_main.c            |    1 +
 drivers/net/r8169.c                     |    2 +-
 drivers/net/s2io.c                      |   13 +------
 drivers/net/sfc/efx.c                   |    1 +
 drivers/net/sfc/ethtool.c               |   16 --------
 drivers/net/skge.c                      |   14 +------
 drivers/net/sky2.c                      |    5 +-
 drivers/net/spider_net.c                |    1 +
 drivers/net/spider_net_ethtool.c        |    1 -
 drivers/net/stmmac/stmmac_ethtool.c     |   13 +------
 drivers/net/tehuti.c                    |   10 -----
 drivers/net/tg3.c                       |   26 +++---------
 drivers/net/typhoon.c                   |    2 +-
 drivers/net/usb/smsc75xx.c              |    6 +-
 drivers/net/usb/smsc95xx.c              |   16 ++------
 drivers/net/veth.c                      |   18 +--------
 drivers/net/via-velocity.c              |    4 +-
 drivers/net/virtio_net.c                |    7 ++-
 drivers/net/vmxnet3/vmxnet3_ethtool.c   |    3 +-
 drivers/net/vxge/vxge-ethtool.c         |    3 +-
 drivers/net/xen-netfront.c              |    2 +-
 drivers/s390/net/qeth_l3_main.c         |   13 ++----
 drivers/staging/octeon/ethernet-mdio.c  |    1 -
 include/linux/ethtool.h                 |   10 +----
 net/bridge/br_device.c                  |    5 +-
 net/core/ethtool.c                      |   64 ++++++++++---------------------
 74 files changed, 118 insertions(+), 535 deletions(-)

diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 04af96a..c9bdf27 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1583,7 +1583,6 @@ static const struct ethtool_ops nes_ethtool_ops = {
 	.get_link = ethtool_op_get_link,
 	.get_settings = nes_netdev_get_settings,
 	.set_settings = nes_netdev_set_settings,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 	.get_rx_csum = nes_netdev_get_rx_csum,
 	.get_strings = nes_netdev_get_strings,
 	.get_sset_count = nes_netdev_get_sset_count,
@@ -1593,7 +1592,6 @@ static const struct ethtool_ops nes_ethtool_ops = {
 	.set_coalesce = nes_netdev_set_coalesce,
 	.get_pauseparam = nes_netdev_get_pauseparam,
 	.set_pauseparam = nes_netdev_set_pauseparam,
-	.set_tx_csum = ethtool_op_set_tx_csum,
 	.set_rx_csum = nes_netdev_set_rx_csum,
 	.get_flags = ethtool_op_get_flags,
 	.set_flags = nes_netdev_set_flags,
@@ -1668,6 +1666,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
 	netdev->type = ARPHRD_ETHER;
 	netdev->features = NETIF_F_HIGHDMA;
 	netdev->netdev_ops = &nes_netdev_ops;
+	netdev->hw_features |= NETIF_F_IP_CSUM;
 	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	netdev->ethtool_ops = &nes_ethtool_ops;
 	netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 0fd2867..ca86398 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1558,7 +1558,6 @@ static const struct ethtool_ops cp_ethtool_ops = {
 	.set_msglevel		= cp_set_msglevel,
 	.get_rx_csum		= cp_get_rx_csum,
 	.set_rx_csum		= cp_set_rx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum, /* local! */
 	.get_regs		= cp_get_regs,
 	.get_wol		= cp_get_wol,
 	.set_wol		= cp_set_wol,
@@ -1956,6 +1955,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	dev->netdev_ops = &cp_netdev_ops;
 	netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
+	dev->hw_features |= NETIF_F_IP_CSUM;
 	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	dev->ethtool_ops = &cp_ethtool_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
index d517223..67d3d36 100644
--- a/drivers/net/atl1c/atl1c_ethtool.c
+++ b/drivers/net/atl1c/atl1c_ethtool.c
@@ -113,11 +113,6 @@ static int atl1c_set_settings(struct net_device *netdev,
 	return 0;
 }
 
-static u32 atl1c_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
 static u32 atl1c_get_msglevel(struct net_device *netdev)
 {
 	struct atl1c_adapter *adapter = netdev_priv(netdev);
@@ -307,7 +302,6 @@ static const struct ethtool_ops atl1c_ethtool_ops = {
 	.get_link               = ethtool_op_get_link,
 	.get_eeprom_len         = atl1c_get_eeprom_len,
 	.get_eeprom             = atl1c_get_eeprom,
-	.get_tx_csum            = atl1c_get_tx_csum,
 };
 
 void atl1c_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c
index 1485797..8164e8c 100644
--- a/drivers/net/atl1e/atl1e_ethtool.c
+++ b/drivers/net/atl1e/atl1e_ethtool.c
@@ -382,11 +382,11 @@ static const struct ethtool_ops atl1e_ethtool_ops = {
 	.get_eeprom_len         = atl1e_get_eeprom_len,
 	.get_eeprom             = atl1e_get_eeprom,
 	.set_eeprom             = atl1e_set_eeprom,
-	.set_tx_csum            = ethtool_op_set_tx_hw_csum,
 };
 
 void atl1e_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &atl1e_ethtool_ops);
 }
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 814a06c..1abf8ce 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -2993,6 +2993,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
 
 	netdev->hw_features |= NETIF_F_SG;
 	netdev->hw_features |= NETIF_F_TSO;
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->ethtool_ops = &atl1_ethtool_ops;
 	adapter->bd_number = cards_found;
 
@@ -3677,7 +3678,6 @@ static const struct ethtool_ops atl1_ethtool_ops = {
 	.get_pauseparam		= atl1_get_pauseparam,
 	.set_pauseparam		= atl1_set_pauseparam,
 	.get_rx_csum		= atl1_get_rx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
 	.get_link		= ethtool_op_get_link,
 	.get_strings		= atl1_get_strings,
 	.nway_reset		= atl1_nway_reset,
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index 0d9b688..76635ec 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -1840,11 +1840,6 @@ static int atl2_set_settings(struct net_device *netdev,
 	return 0;
 }
 
-static u32 atl2_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
 static u32 atl2_get_msglevel(struct net_device *netdev)
 {
 	return 0;
@@ -2106,7 +2101,6 @@ static const struct ethtool_ops atl2_ethtool_ops = {
 	.get_eeprom_len		= atl2_get_eeprom_len,
 	.get_eeprom		= atl2_get_eeprom,
 	.set_eeprom		= atl2_set_eeprom,
-	.get_tx_csum		= atl2_get_tx_csum,
 };
 
 static void atl2_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 8c1eaee..727cce9 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -696,8 +696,6 @@ const struct ethtool_ops be_ethtool_ops = {
 	.set_pauseparam = be_set_pauseparam,
 	.get_rx_csum = be_get_rx_csum,
 	.set_rx_csum = be_set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.set_tx_csum = ethtool_op_set_tx_hw_csum,
 	.get_strings = be_get_stat_strings,
 	.phys_id = be_phys_id,
 	.get_sset_count = be_get_sset_count,
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index b8a164f..1081e32 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -2554,6 +2554,7 @@ static void be_netdev_init(struct net_device *netdev)
 
 	BE_SET_NETDEV_OPS(netdev, &be_netdev_ops);
 
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
 
diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c
index f8bdebf..fe90c2a 100644
--- a/drivers/net/bna/bnad_ethtool.c
+++ b/drivers/net/bna/bnad_ethtool.c
@@ -831,23 +831,6 @@ bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum)
 	return 0;
 }
 
-static int
-bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum)
-{
-	struct bnad *bnad = netdev_priv(netdev);
-
-	mutex_lock(&bnad->conf_mutex);
-	if (tx_csum) {
-		netdev->features |= NETIF_F_IP_CSUM;
-		netdev->features |= NETIF_F_IPV6_CSUM;
-	} else {
-		netdev->features &= ~NETIF_F_IP_CSUM;
-		netdev->features &= ~NETIF_F_IPV6_CSUM;
-	}
-	mutex_unlock(&bnad->conf_mutex);
-	return 0;
-}
-
 static void
 bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
 {
@@ -1242,8 +1225,6 @@ static struct ethtool_ops bnad_ethtool_ops = {
 	.set_pauseparam = bnad_set_pauseparam,
 	.get_rx_csum = bnad_get_rx_csum,
 	.set_rx_csum = bnad_set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.set_tx_csum = bnad_set_tx_csum,
 	.get_strings = bnad_get_strings,
 	.get_ethtool_stats = bnad_get_ethtool_stats,
 	.get_sset_count = bnad_get_sset_count
@@ -1254,5 +1235,6 @@ bnad_set_ethtool_ops(struct net_device *netdev)
 {
 	netdev->hw_features |= NETIF_F_SG;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
+	netdev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
 	SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
 }
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 8a63a8b..c2a1d3e 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -7495,17 +7495,6 @@ bnx2_phys_id(struct net_device *dev, u32 data)
 }
 
 static int
-bnx2_set_tx_csum(struct net_device *dev, u32 data)
-{
-	struct bnx2 *bp = netdev_priv(dev);
-
-	if (CHIP_NUM(bp) == CHIP_NUM_5709)
-		return ethtool_op_set_tx_ipv6_csum(dev, data);
-	else
-		return ethtool_op_set_tx_csum(dev, data);
-}
-
-static int
 bnx2_set_flags(struct net_device *dev, u32 data)
 {
 	struct bnx2 *bp = netdev_priv(dev);
@@ -7553,7 +7542,6 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
 	.set_pauseparam		= bnx2_set_pauseparam,
 	.get_rx_csum		= bnx2_get_rx_csum,
 	.set_rx_csum		= bnx2_set_rx_csum,
-	.set_tx_csum		= bnx2_set_tx_csum,
 	.self_test		= bnx2_self_test,
 	.get_strings		= bnx2_get_strings,
 	.phys_id		= bnx2_phys_id,
@@ -8303,7 +8291,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	dev->netdev_ops = &bnx2_netdev_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_IP_CSUM;
 	dev->hw_features |= NETIF_F_TSO|NETIF_F_TSO_ECN;
 	dev->ethtool_ops = &bnx2_ethtool_ops;
 
@@ -8322,6 +8310,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 			 NETIF_F_RXHASH;
 	vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
 	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		dev->hw_features |= NETIF_F_IPV6_CSUM;
 		dev->features |= NETIF_F_IPV6_CSUM;
 		vlan_features_add(dev, NETIF_F_IPV6_CSUM);
 	}
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
index 3d08714..6b15243 100644
--- a/drivers/net/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -2065,8 +2065,6 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
 	.set_pauseparam		= bnx2x_set_pauseparam,
 	.get_rx_csum		= bnx2x_get_rx_csum,
 	.set_rx_csum		= bnx2x_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
 	.set_flags		= bnx2x_set_flags,
 	.get_flags		= ethtool_op_get_flags,
 	.self_test		= bnx2x_self_test,
@@ -2078,7 +2076,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
 
 void bnx2x_set_ethtool_ops(struct net_device *netdev)
 {
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO_ECN|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &bnx2x_ethtool_ops);
 }
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 4e030c5..29b0ea8 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4650,7 +4650,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
 static const struct ethtool_ops bond_ethtool_ops = {
 	.get_drvinfo		= bond_ethtool_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.get_ufo		= ethtool_op_get_ufo,
 	.get_flags		= ethtool_op_get_flags,
 };
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 712c413..c8acac9 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -824,7 +824,6 @@ static const struct ethtool_ops t1_ethtool_ops = {
 	.set_pauseparam    = set_pauseparam,
 	.get_rx_csum       = get_rx_csum,
 	.set_rx_csum       = set_rx_csum,
-	.set_tx_csum       = ethtool_op_set_tx_csum,
 	.get_link          = ethtool_op_get_link,
 	.get_strings       = get_strings,
 	.get_sset_count	   = get_sset_count,
@@ -1120,7 +1119,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 
 		netif_napi_add(netdev, &adapter->napi, t1_poll, 64);
 
-		netdev->hw_features |= NETIF_F_SG;
+		netdev->hw_features |= NETIF_F_SG|NETIF_F_IP_CSUM;
 		if (adapter->flags & TSO_CAPABLE)
 			netdev->hw_features |= NETIF_F_TSO;
 		SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 1d45f7d..1110364 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2096,7 +2096,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
 	.set_pauseparam = set_pauseparam,
 	.get_rx_csum = get_rx_csum,
 	.set_rx_csum = set_rx_csum,
-	.set_tx_csum = ethtool_op_set_tx_csum,
 	.get_link = ethtool_op_get_link,
 	.get_strings = get_strings,
 	.phys_id = cxgb3_phys_id,
@@ -3309,6 +3308,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 
 		netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 		netdev->netdev_ops = &cxgb_netdev_ops;
+		netdev->hw_features |= NETIF_F_IP_CSUM;
 		netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
 	}
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 700bb37..41f14b1 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -2001,7 +2001,6 @@ static struct ethtool_ops cxgb_ethtool_ops = {
 	.set_pauseparam    = set_pauseparam,
 	.get_rx_csum       = get_rx_csum,
 	.set_rx_csum       = set_rx_csum,
-	.set_tx_csum       = ethtool_op_set_tx_ipv6_csum,
 	.get_link          = ethtool_op_get_link,
 	.get_strings       = get_strings,
 	.phys_id           = identify_port,
@@ -3663,6 +3662,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 		netdev->vlan_features = netdev->features & VLAN_FEAT;
 
 		netdev->netdev_ops = &cxgb4_netdev_ops;
+		netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 		netdev->hw_features |= NETIF_F_SG | TSO_FLAGS;
 		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
 	}
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 61cc28c..a6b1a5f 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -1551,7 +1551,6 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = {
 	.get_pauseparam		= cxgb4vf_get_pauseparam,
 	.get_rx_csum		= cxgb4vf_get_rx_csum,
 	.set_rx_csum		= cxgb4vf_set_rx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_ipv6_csum,
 	.get_link		= ethtool_op_get_link,
 	.get_strings		= cxgb4vf_get_strings,
 	.phys_id		= cxgb4vf_phys_id,
@@ -2616,6 +2615,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
 		netdev->poll_controller = cxgb4vf_poll_controller;
 #endif
 #endif
+		netdev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
 		netdev->hw_features |= NETIF_F_SG;
 		netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 		SET_ETHTOOL_OPS(netdev, &cxgb4vf_ethtool_ops);
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 9f6aeef..5ba4535 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -132,7 +132,6 @@ typedef struct board_info {
 	u32		wake_state;
 
 	int		rx_csum;
-	int		can_csum;
 	int		ip_summed;
 } board_info_t;
 
@@ -480,7 +479,7 @@ static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data)
 {
 	board_info_t *dm = to_dm9000_board(dev);
 
-	if (dm->can_csum) {
+	if (dev->hw_features & NETIF_F_IP_CSUM) {
 		dm->rx_csum = data;
 		iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0);
 
@@ -503,16 +502,6 @@ static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
 	return ret;
 }
 
-static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data)
-{
-	board_info_t *dm = to_dm9000_board(dev);
-	int ret = -EOPNOTSUPP;
-
-	if (dm->can_csum)
-		ret = ethtool_op_set_tx_csum(dev, data);
-	return ret;
-}
-
 static u32 dm9000_get_link(struct net_device *dev)
 {
 	board_info_t *dm = to_dm9000_board(dev);
@@ -645,8 +634,6 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
  	.set_eeprom		= dm9000_set_eeprom,
 	.get_rx_csum		= dm9000_get_rx_csum,
 	.set_rx_csum		= dm9000_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= dm9000_set_tx_csum,
 };
 
 static void dm9000_show_carrier(board_info_t *db,
@@ -1550,9 +1537,9 @@ dm9000_probe(struct platform_device *pdev)
 
 	/* dm9000a/b are capable of hardware checksum offload */
 	if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
-		db->can_csum = 1;
 		db->rx_csum = 1;
 		ndev->features |= NETIF_F_IP_CSUM;
+		ndev->hw_features |= NETIF_F_IP_CSUM;
 	}
 
 	/* from this point we assume that we have found a DM9000 */
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index fcde1b2..ddcb371 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -306,30 +306,6 @@ static int e1000_set_rx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static u32 e1000_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
-static int e1000_set_tx_csum(struct net_device *netdev, u32 data)
-{
-	struct e1000_adapter *adapter = netdev_priv(netdev);
-	struct e1000_hw *hw = &adapter->hw;
-
-	if (hw->mac_type < e1000_82543) {
-		if (!data)
-			return -EINVAL;
-		return 0;
-	}
-
-	if (data)
-		netdev->features |= NETIF_F_HW_CSUM;
-	else
-		netdev->features &= ~NETIF_F_HW_CSUM;
-
-	return 0;
-}
-
 static u32 e1000_get_msglevel(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1902,8 +1878,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 	.set_pauseparam         = e1000_set_pauseparam,
 	.get_rx_csum            = e1000_get_rx_csum,
 	.set_rx_csum            = e1000_set_rx_csum,
-	.get_tx_csum            = e1000_get_tx_csum,
-	.set_tx_csum            = e1000_set_tx_csum,
 	.self_test              = e1000_diag_test,
 	.get_strings            = e1000_get_strings,
 	.phys_id                = e1000_phys_id,
@@ -1917,6 +1891,8 @@ void e1000_set_ethtool_ops(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 
+	if (!(adapter->hw.mac_type < e1000_82543))
+		netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_SG;
 	if (!(adapter->hw.mac_type < e1000_82544) &&
 	    !(adapter->hw.mac_type == e1000_82547))
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 579ed4b..8e7b312 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -387,21 +387,6 @@ static int e1000_set_rx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static u32 e1000_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
-static int e1000_set_tx_csum(struct net_device *netdev, u32 data)
-{
-	if (data)
-		netdev->features |= NETIF_F_HW_CSUM;
-	else
-		netdev->features &= ~NETIF_F_HW_CSUM;
-
-	return 0;
-}
-
 static int e1000_set_tso(struct net_device *netdev, u32 data)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -2026,8 +2011,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 	.set_pauseparam		= e1000_set_pauseparam,
 	.get_rx_csum		= e1000_get_rx_csum,
 	.set_rx_csum		= e1000_set_rx_csum,
-	.get_tx_csum		= e1000_get_tx_csum,
-	.set_tx_csum		= e1000_set_tx_csum,
 	.hw_set_tso		= e1000_set_tso,
 	.self_test		= e1000_diag_test,
 	.get_strings		= e1000_get_strings,
@@ -2041,7 +2024,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
 
 void e1000e_set_ethtool_ops(struct net_device *netdev)
 {
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
 }
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 88e4a99..e1077e6 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -297,11 +297,6 @@ static int enic_set_tx_csum(struct net_device *netdev, u32 data)
 	if (data && !ENIC_SETTING(enic, TXCSUM))
 		return -EINVAL;
 
-	if (data)
-		netdev->features |= NETIF_F_HW_CSUM;
-	else
-		netdev->features &= ~NETIF_F_HW_CSUM;
-
 	return 0;
 }
 
@@ -404,8 +399,7 @@ static const struct ethtool_ops enic_ethtool_ops = {
 	.get_ethtool_stats = enic_get_ethtool_stats,
 	.get_rx_csum = enic_get_rx_csum,
 	.set_rx_csum = enic_set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.set_tx_csum = enic_set_tx_csum,
+	.hw_set_tx_csum = enic_set_tx_csum,
 	.hw_set_tso = enic_set_tso,
 	.get_coalesce = enic_get_coalesce,
 	.set_coalesce = enic_set_coalesce,
@@ -2628,6 +2622,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
 		netdev->netdev_ops = &enic_netdev_ops;
 
 	netdev->watchdog_timeo = 2 * HZ;
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_SG;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6|NETIF_F_TSO_ECN;
 	netdev->ethtool_ops = &enic_ethtool_ops;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 8aabb6a..3d5a9af 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -4638,16 +4638,6 @@ static int nv_set_rx_csum(struct net_device *dev, u32 data)
 	return retcode;
 }
 
-static int nv_set_tx_csum(struct net_device *dev, u32 data)
-{
-	struct fe_priv *np = netdev_priv(dev);
-
-	if (np->driver_data & DEV_HAS_CHECKSUM)
-		return ethtool_op_set_tx_csum(dev, data);
-	else
-		return -EOPNOTSUPP;
-}
-
 static int nv_get_sset_count(struct net_device *dev, int sset)
 {
 	struct fe_priv *np = netdev_priv(dev);
@@ -5025,7 +5015,6 @@ static const struct ethtool_ops ops = {
 	.set_pauseparam = nv_set_pauseparam,
 	.get_rx_csum = nv_get_rx_csum,
 	.set_rx_csum = nv_set_rx_csum,
-	.set_tx_csum = nv_set_tx_csum,
 	.get_strings = nv_get_strings,
 	.get_ethtool_stats = nv_get_ethtool_stats,
 	.get_sset_count = nv_get_sset_count,
@@ -5554,7 +5543,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 
 	netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP);
 	if (np->driver_data & DEV_HAS_CHECKSUM)
-		dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
+		dev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &ops);
 	dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
 
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 4f1adcb..9e12457 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -955,7 +955,6 @@ static const struct ethtool_ops fs_ethtool_ops = {
 	.get_link = ethtool_op_get_link,
 	.get_msglevel = fs_get_msglevel,
 	.set_msglevel = fs_set_msglevel,
-	.set_tx_csum = ethtool_op_set_tx_csum,	/* local! */
 	.get_regs = fs_get_regs,
 };
 
@@ -1077,7 +1076,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev,
 		netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi,
 		               fpi->napi_weight);
 
-	ndev->hw_features |= NETIF_F_SG;
+	ndev->hw_features |= NETIF_F_SG|NETIF_F_IP_CSUM;
 	ndev->ethtool_ops = &fs_ethtool_ops;
 
 	init_timer(&fep->phy_timer_list);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index c34b1cc..f597080 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1030,6 +1030,7 @@ static int gfar_probe(struct platform_device *ofdev,
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
 		priv->rx_csum_enable = 1;
+		dev->hw_features |= NETIF_F_IP_CSUM;
 		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA;
 	} else
 		priv->rx_csum_enable = 0;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index cf4a87a..79c7a9e 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -569,35 +569,6 @@ static uint32_t gfar_get_rx_csum(struct net_device *dev)
 	return priv->rx_csum_enable;
 }
 
-static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
-{
-	struct gfar_private *priv = netdev_priv(dev);
-
-	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
-		return -EOPNOTSUPP;
-
-	netif_tx_lock_bh(dev);
-
-	if (data)
-		dev->features |= NETIF_F_IP_CSUM;
-	else
-		dev->features &= ~NETIF_F_IP_CSUM;
-
-	netif_tx_unlock_bh(dev);
-
-	return 0;
-}
-
-static uint32_t gfar_get_tx_csum(struct net_device *dev)
-{
-	struct gfar_private *priv = netdev_priv(dev);
-
-	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
-		return 0;
-
-	return (dev->features & NETIF_F_IP_CSUM) != 0;
-}
-
 static uint32_t gfar_get_msglevel(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
@@ -894,9 +865,7 @@ const struct ethtool_ops gfar_ethtool_ops = {
 	.get_sset_count = gfar_sset_count,
 	.get_ethtool_stats = gfar_fill_stats,
 	.get_rx_csum = gfar_get_rx_csum,
-	.get_tx_csum = gfar_get_tx_csum,
 	.set_rx_csum = gfar_set_rx_csum,
-	.set_tx_csum = gfar_set_tx_csum,
 	.get_msglevel = gfar_get_msglevel,
 	.set_msglevel = gfar_set_msglevel,
 #ifdef CONFIG_PM
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 27d6960..bc3b25e 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -1123,19 +1123,6 @@ static int greth_set_rx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static u32 greth_get_tx_csum(struct net_device *dev)
-{
-	return (dev->features & NETIF_F_IP_CSUM) != 0;
-}
-
-static int greth_set_tx_csum(struct net_device *dev, u32 data)
-{
-	netif_tx_lock_bh(dev);
-	ethtool_op_set_tx_csum(dev, data);
-	netif_tx_unlock_bh(dev);
-	return 0;
-}
-
 static const struct ethtool_ops greth_ethtool_ops = {
 	.get_msglevel		= greth_get_msglevel,
 	.set_msglevel		= greth_set_msglevel,
@@ -1146,8 +1133,6 @@ static const struct ethtool_ops greth_ethtool_ops = {
 	.get_regs               = greth_get_regs,
 	.get_rx_csum		= greth_get_rx_csum,
 	.set_rx_csum		= greth_set_rx_csum,
-	.get_tx_csum		= greth_get_tx_csum,
-	.set_tx_csum		= greth_set_tx_csum,
 	.get_link		= ethtool_op_get_link,
 };
 
@@ -1546,6 +1531,7 @@ static int __devinit greth_of_probe(struct platform_device *ofdev, const struct
 
 	dev->netdev_ops = &greth_netdev_ops;
 	dev->ethtool_ops = &greth_ethtool_ops;
+	dev->hw_features = NETIF_F_IP_CSUM;
 
 	err = register_netdev(dev);
 	if (err) {
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 7f3ccc2..b07474b 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -2210,7 +2210,6 @@ static const struct ethtool_ops emac_ethtool_ops = {
 	.get_ethtool_stats = emac_ethtool_get_ethtool_stats,
 
 	.get_link = ethtool_op_get_link,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 };
 
 static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 7e96672..eafb61f 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -875,7 +875,7 @@ static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
 	else
 		ibmveth_set_tx_csum_flags(dev, data);
 
-	return rc;
+	return rc ? rc : 1;
 }
 
 static u32 ibmveth_get_rx_csum(struct net_device *dev)
@@ -919,7 +919,7 @@ static const struct ethtool_ops netdev_ethtool_ops = {
 	.get_drvinfo		= netdev_get_drvinfo,
 	.get_settings		= netdev_get_settings,
 	.get_link		= netdev_get_link,
-	.set_tx_csum		= ibmveth_set_tx_csum,
+	.hw_set_tx_csum		= ibmveth_set_tx_csum,
 	.get_rx_csum		= ibmveth_get_rx_csum,
 	.set_rx_csum		= ibmveth_set_rx_csum,
 	.get_strings		= ibmveth_get_strings,
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index de257e4..e73b7eb 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -334,27 +334,6 @@ static int igb_set_rx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static u32 igb_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_IP_CSUM) != 0;
-}
-
-static int igb_set_tx_csum(struct net_device *netdev, u32 data)
-{
-	struct igb_adapter *adapter = netdev_priv(netdev);
-
-	if (data) {
-		netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-		if (adapter->hw.mac.type >= e1000_82576)
-			netdev->features |= NETIF_F_SCTP_CSUM;
-	} else {
-		netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-		                      NETIF_F_SCTP_CSUM);
-	}
-
-	return 0;
-}
-
 static u32 igb_get_msglevel(struct net_device *netdev)
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
@@ -2174,8 +2153,6 @@ static const struct ethtool_ops igb_ethtool_ops = {
 	.set_pauseparam         = igb_set_pauseparam,
 	.get_rx_csum            = igb_get_rx_csum,
 	.set_rx_csum            = igb_set_rx_csum,
-	.get_tx_csum            = igb_get_tx_csum,
-	.set_tx_csum            = igb_set_tx_csum,
 	.self_test              = igb_diag_test,
 	.get_strings            = igb_get_strings,
 	.phys_id                = igb_phys_id,
@@ -2187,7 +2164,12 @@ static const struct ethtool_ops igb_ethtool_ops = {
 
 void igb_set_ethtool_ops(struct net_device *netdev)
 {
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
 	netdev->hw_features |= NETIF_F_SG;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
+	netdev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
+	if (adapter->hw.mac.type >= e1000_82576)
+		netdev->hw_features |= NETIF_F_SCTP_CSUM;
 	SET_ETHTOOL_OPS(netdev, &igb_ethtool_ops);
 }
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
index 56f77b6..469f00f 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -151,20 +151,6 @@ static int igbvf_set_rx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static u32 igbvf_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_IP_CSUM) != 0;
-}
-
-static int igbvf_set_tx_csum(struct net_device *netdev, u32 data)
-{
-	if (data)
-		netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-	else
-		netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-	return 0;
-}
-
 static u32 igbvf_get_msglevel(struct net_device *netdev)
 {
 	struct igbvf_adapter *adapter = netdev_priv(netdev);
@@ -508,8 +494,6 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
 	.set_pauseparam		= igbvf_set_pauseparam,
 	.get_rx_csum            = igbvf_get_rx_csum,
 	.set_rx_csum            = igbvf_set_rx_csum,
-	.get_tx_csum		= igbvf_get_tx_csum,
-	.set_tx_csum		= igbvf_set_tx_csum,
 	.self_test		= igbvf_diag_test,
 	.get_sset_count		= igbvf_get_sset_count,
 	.get_strings		= igbvf_get_strings,
@@ -521,6 +505,7 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
 
 void igbvf_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
 	netdev->hw_features |= NETIF_F_SG;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	/* have to "undeclare" const on this struct to remove warnings */
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index c8ee8d2..0792963 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -1327,6 +1327,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
 	/* The IOC3-specific entries in the device structure. */
 	dev->watchdog_timeo	= 5 * HZ;
 	dev->netdev_ops		= &ioc3_netdev_ops;
+	dev->hw_features	= NETIF_F_IP_CSUM;
 	dev->ethtool_ops	= &ioc3_ethtool_ops;
 	dev->features		= NETIF_F_IP_CSUM;
 
@@ -1647,8 +1648,6 @@ static const struct ethtool_ops ioc3_ethtool_ops = {
 	.get_link		= ioc3_get_link,
 	.get_rx_csum		= ioc3_get_rx_csum,
 	.set_rx_csum		= ioc3_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum
 };
 
 static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index b8b38ef..1d9c232 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -218,23 +218,6 @@ ixgb_set_rx_csum(struct net_device *netdev, u32 data)
 }
 
 static u32
-ixgb_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
-static int
-ixgb_set_tx_csum(struct net_device *netdev, u32 data)
-{
-	if (data)
-		netdev->features |= NETIF_F_HW_CSUM;
-	else
-		netdev->features &= ~NETIF_F_HW_CSUM;
-
-	return 0;
-}
-
-static u32
 ixgb_get_msglevel(struct net_device *netdev)
 {
 	struct ixgb_adapter *adapter = netdev_priv(netdev);
@@ -712,8 +695,6 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
 	.set_pauseparam	= ixgb_set_pauseparam,
 	.get_rx_csum = ixgb_get_rx_csum,
 	.set_rx_csum = ixgb_set_rx_csum,
-	.get_tx_csum = ixgb_get_tx_csum,
-	.set_tx_csum = ixgb_set_tx_csum,
 	.get_msglevel = ixgb_get_msglevel,
 	.set_msglevel = ixgb_set_msglevel,
 	.get_strings = ixgb_get_strings,
@@ -724,6 +705,7 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
 
 void ixgb_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &ixgb_ethtool_ops);
 }
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 561a74d..d14c0eb 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -420,28 +420,6 @@ static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
 	return 0;
 }
 
-static u32 ixgbe_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_IP_CSUM) != 0;
-}
-
-static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data)
-{
-	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-
-	if (data) {
-		netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-		if (adapter->hw.mac.type == ixgbe_mac_82599EB)
-			netdev->features |= NETIF_F_SCTP_CSUM;
-	} else {
-		netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-		if (adapter->hw.mac.type == ixgbe_mac_82599EB)
-			netdev->features &= ~NETIF_F_SCTP_CSUM;
-	}
-
-	return 0;
-}
-
 static u32 ixgbe_get_msglevel(struct net_device *netdev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -2273,8 +2251,6 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
 	.set_pauseparam         = ixgbe_set_pauseparam,
 	.get_rx_csum            = ixgbe_get_rx_csum,
 	.set_rx_csum            = ixgbe_set_rx_csum,
-	.get_tx_csum            = ixgbe_get_tx_csum,
-	.set_tx_csum            = ixgbe_set_tx_csum,
 	.get_msglevel           = ixgbe_get_msglevel,
 	.set_msglevel           = ixgbe_set_msglevel,
 	.self_test              = ixgbe_diag_test,
@@ -2291,7 +2267,13 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
 
 void ixgbe_set_ethtool_ops(struct net_device *netdev)
 {
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	netdev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
+	if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+		netdev->hw_features |= NETIF_F_SCTP_CSUM;
 	netdev->hw_features |= NETIF_F_SG;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
+
 	SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops);
 }
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
index 58ae092..673dedd 100644
--- a/drivers/net/ixgbevf/ethtool.c
+++ b/drivers/net/ixgbevf/ethtool.c
@@ -702,8 +702,6 @@ static struct ethtool_ops ixgbevf_ethtool_ops = {
 	.set_ringparam          = ixgbevf_set_ringparam,
 	.get_rx_csum            = ixgbevf_get_rx_csum,
 	.set_rx_csum            = ixgbevf_set_rx_csum,
-	.get_tx_csum            = ethtool_op_get_tx_csum,
-	.set_tx_csum            = ethtool_op_set_tx_ipv6_csum,
 	.get_msglevel           = ixgbevf_get_msglevel,
 	.set_msglevel           = ixgbevf_set_msglevel,
 	.self_test              = ixgbevf_diag_test,
@@ -714,6 +712,7 @@ static struct ethtool_ops ixgbevf_ethtool_ops = {
 
 void ixgbevf_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
 	netdev->hw_features |= NETIF_F_SG;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &ixgbevf_ethtool_ops);
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index f837c3f..96feccd 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -2513,11 +2513,10 @@ jme_set_tx_csum(struct net_device *netdev, u32 on)
 
 	if (on) {
 		set_bit(JME_FLAG_TXCSUM, &jme->flags);
-		if (netdev->mtu <= 1900)
-			netdev->features |= NETIF_F_HW_CSUM;
+		if (netdev->mtu > 1900)
+			return 1;
 	} else {
 		clear_bit(JME_FLAG_TXCSUM, &jme->flags);
-		netdev->features &= ~NETIF_F_HW_CSUM;
 	}
 
 	return 0;
@@ -2682,7 +2681,7 @@ static const struct ethtool_ops jme_ethtool_ops = {
 	.set_msglevel           = jme_set_msglevel,
 	.get_rx_csum		= jme_get_rx_csum,
 	.set_rx_csum		= jme_set_rx_csum,
-	.set_tx_csum		= jme_set_tx_csum,
+	.hw_set_tx_csum		= jme_set_tx_csum,
 	.hw_set_tso		= jme_set_tso,
 	.nway_reset             = jme_nway_reset,
 	.get_eeprom_len		= jme_get_eeprom_len,
@@ -2793,6 +2792,7 @@ jme_init_one(struct pci_dev *pdev,
 		goto err_out_release_regions;
 	}
 	netdev->netdev_ops = &jme_netdev_ops;
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6;
 	netdev->ethtool_ops		= &jme_ethtool_ops;
 	netdev->watchdog_timeo		= TX_TIMEOUT;
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c
index ea69576..f8669d2 100644
--- a/drivers/net/ksz884x.c
+++ b/drivers/net/ksz884x.c
@@ -6660,8 +6660,6 @@ static struct ethtool_ops netdev_ethtool_ops = {
 	.get_ethtool_stats	= netdev_get_ethtool_stats,
 	.get_rx_csum		= netdev_get_rx_csum,
 	.set_rx_csum		= netdev_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum,
 };
 
 /*
@@ -7148,6 +7146,7 @@ static int __init pcidev_init(struct pci_dev *pdev,
 		}
 
 		dev->netdev_ops = &netdev_ops;
+		dev->hw_features |= NETIF_F_IP_CSUM;
 		dev->hw_features |= NETIF_F_SG;
 		SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 		if (register_netdev(dev))
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 76e900c..411a4d9 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -129,7 +129,6 @@ static u32 always_on(struct net_device *dev)
 
 static const struct ethtool_ops loopback_ethtool_ops = {
 	.get_link		= always_on,
-	.get_tx_csum		= always_on,
 	.get_rx_csum		= always_on,
 };
 
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index a963bcd..84ee1c8 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -422,8 +422,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
 	.get_link = ethtool_op_get_link,
 	.get_rx_csum = mlx4_en_get_rx_csum,
 	.set_rx_csum = mlx4_en_set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.set_tx_csum = ethtool_op_set_tx_ipv6_csum,
 	.get_strings = mlx4_en_get_strings,
 	.get_sset_count = mlx4_en_get_sset_count,
 	.get_ethtool_stats = mlx4_en_get_ethtool_stats,
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index b867b34..ecf1710 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -1038,6 +1038,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
 	netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
 
+	dev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
 	dev->hw_features |= NETIF_F_SG;
 	dev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index aa3b981..95d2393 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1665,7 +1665,6 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
 	.set_ringparam		= mv643xx_eth_set_ringparam,
 	.get_rx_csum		= mv643xx_eth_get_rx_csum,
 	.set_rx_csum		= mv643xx_eth_set_rx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum,
 	.get_strings		= mv643xx_eth_get_strings,
 	.get_ethtool_stats	= mv643xx_eth_get_ethtool_stats,
 	.get_flags		= ethtool_op_get_flags,
@@ -2909,7 +2908,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
 	if (mp->phy != NULL)
 		phy_init(mp, pd->speed, pd->duplex);
 
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_IP_CSUM;
 	SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
 
 	init_pscr(mp, pd->speed, pd->duplex);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 4f8b838..5ac8dd7 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1938,7 +1938,6 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
 	.get_ringparam = myri10ge_get_ringparam,
 	.get_rx_csum = myri10ge_get_rx_csum,
 	.set_rx_csum = myri10ge_set_rx_csum,
-	.set_tx_csum = ethtool_op_set_tx_hw_csum,
 	.get_link = ethtool_op_get_link,
 	.get_strings = myri10ge_get_strings,
 	.get_sset_count = myri10ge_get_sset_count,
@@ -3984,7 +3983,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		    (unsigned long)mgp);
 
 	spin_lock_init(&mgp->stats_lock);
-	netdev->hw_features |= NETIF_F_SG;
+	netdev->hw_features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops);
 	INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 9244bb1..c8cdbba 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -706,11 +706,6 @@ netxen_nic_get_ethtool_stats(struct net_device *dev,
 	}
 }
 
-static u32 netxen_nic_get_tx_csum(struct net_device *dev)
-{
-	return dev->features & NETIF_F_IP_CSUM;
-}
-
 static u32 netxen_nic_get_rx_csum(struct net_device *dev)
 {
 	struct netxen_adapter *adapter = netdev_priv(dev);
@@ -900,8 +895,6 @@ const struct ethtool_ops netxen_nic_ethtool_ops = {
 	.set_ringparam = netxen_nic_set_ringparam,
 	.get_pauseparam = netxen_nic_get_pauseparam,
 	.set_pauseparam = netxen_nic_set_pauseparam,
-	.get_tx_csum = netxen_nic_get_tx_csum,
-	.set_tx_csum = ethtool_op_set_tx_csum,
 	.get_wol = netxen_nic_get_wol,
 	.set_wol = netxen_nic_set_wol,
 	.self_test = netxen_nic_diag_test,
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 573e51f..06672e5 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -1210,6 +1210,7 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
 
 	netxen_nic_change_mtu(netdev, netdev->mtu);
 
+	netdev->hw_features |= NETIF_F_IP_CSUM;
 	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 		netdev->hw_features |= NETIF_F_TSO6;
diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/pch_gbe/pch_gbe_ethtool.c
index c8cc32c..2575c72 100644
--- a/drivers/net/pch_gbe/pch_gbe_ethtool.c
+++ b/drivers/net/pch_gbe/pch_gbe_ethtool.c
@@ -469,18 +469,6 @@ static int pch_gbe_set_rx_csum(struct net_device *netdev, u32 data)
 }
 
 /**
- * pch_gbe_get_tx_csum - Report whether transmit checksums are turned on or off
- * @netdev:  Network interface device structure
- * Returns
- *	true(1):  Checksum On
- *	false(0): Checksum Off
- */
-static u32 pch_gbe_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
-/**
  * pch_gbe_set_tx_csum - Turn transmit checksums on or off
  * @netdev: Network interface device structure
  * @data:   Checksum on[true] or off[false]
@@ -493,10 +481,6 @@ static int pch_gbe_set_tx_csum(struct net_device *netdev, u32 data)
 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
 
 	adapter->tx_csum = data;
-	if (data)
-		netdev->features |= NETIF_F_HW_CSUM;
-	else
-		netdev->features &= ~NETIF_F_HW_CSUM;
 	return 0;
 }
 
@@ -572,8 +556,7 @@ static const struct ethtool_ops pch_gbe_ethtool_ops = {
 	.set_pauseparam = pch_gbe_set_pauseparam,
 	.get_rx_csum = pch_gbe_get_rx_csum,
 	.set_rx_csum = pch_gbe_set_rx_csum,
-	.get_tx_csum = pch_gbe_get_tx_csum,
-	.set_tx_csum = pch_gbe_set_tx_csum,
+	.hw_set_tx_csum = pch_gbe_set_tx_csum,
 	.get_strings = pch_gbe_get_strings,
 	.get_ethtool_stats = pch_gbe_get_ethtool_stats,
 	.get_sset_count = pch_gbe_get_sset_count,
@@ -581,5 +564,6 @@ static const struct ethtool_ops pch_gbe_ethtool_ops = {
 
 void pch_gbe_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	SET_ETHTOOL_OPS(netdev, &pch_gbe_ethtool_ops);
 }
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 5ecfa4b..ec2f5a5 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -1411,8 +1411,6 @@ static const struct ethtool_ops gelic_ether_ethtool_ops = {
 	.get_settings	= gelic_ether_get_settings,
 	.set_settings	= gelic_ether_set_settings,
 	.get_link	= ethtool_op_get_link,
-	.get_tx_csum	= ethtool_op_get_tx_csum,
-	.set_tx_csum	= ethtool_op_set_tx_csum,
 	.get_rx_csum	= gelic_net_get_rx_csum,
 	.set_rx_csum	= gelic_net_set_rx_csum,
 	.get_wol	= gelic_net_get_wol,
@@ -1492,6 +1490,7 @@ static void __devinit gelic_ether_setup_netdev_ops(struct net_device *netdev,
 	/* NAPI */
 	netif_napi_add(netdev, napi,
 		       gelic_net_poll, GELIC_NET_NAPI_WEIGHT);
+	netdev->hw_features |= NETIF_F_IP_CSUM;
 	netdev->ethtool_ops = &gelic_ether_ethtool_ops;
 	netdev->netdev_ops = &gelic_netdevice_ops;
 }
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index 4a624a2..6e3a41e 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -2581,8 +2581,6 @@ static const struct net_device_ops gelic_wl_netdevice_ops = {
 static const struct ethtool_ops gelic_wl_ethtool_ops = {
 	.get_drvinfo	= gelic_net_get_drvinfo,
 	.get_link	= gelic_wl_get_link,
-	.get_tx_csum	= ethtool_op_get_tx_csum,
-	.set_tx_csum	= ethtool_op_set_tx_csum,
 	.get_rx_csum	= gelic_net_get_rx_csum,
 	.set_rx_csum	= gelic_net_set_rx_csum,
 };
@@ -2594,6 +2592,7 @@ static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev)
 	BUG_ON(!wl);
 	netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
 
+	netdev->hw_features |= NETIF_F_IP_CSUM;
 	netdev->ethtool_ops = &gelic_wl_ethtool_ops;
 	netdev->netdev_ops = &gelic_wl_netdevice_ops;
 	netdev->wireless_data = &wl->wireless_data;
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index abf89ba..0da9461 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -883,25 +883,6 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
 	qlcnic_fill_device_stats(&index, data, &port_stats.tx);
 }
 
-static int qlcnic_set_tx_csum(struct net_device *dev, u32 data)
-{
-	struct qlcnic_adapter *adapter = netdev_priv(dev);
-
-	if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
-		return -EOPNOTSUPP;
-	if (data)
-		dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-	else
-		dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-
-	return 0;
-
-}
-static u32 qlcnic_get_tx_csum(struct net_device *dev)
-{
-	return dev->features & NETIF_F_IP_CSUM;
-}
-
 static u32 qlcnic_get_rx_csum(struct net_device *dev)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
@@ -1146,8 +1127,6 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
 	.set_ringparam = qlcnic_set_ringparam,
 	.get_pauseparam = qlcnic_get_pauseparam,
 	.set_pauseparam = qlcnic_set_pauseparam,
-	.get_tx_csum = qlcnic_get_tx_csum,
-	.set_tx_csum = qlcnic_set_tx_csum,
 	.get_wol = qlcnic_get_wol,
 	.set_wol = qlcnic_set_wol,
 	.self_test = qlcnic_diag_test,
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 53e07ed..f5236cb 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -1425,6 +1425,8 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
 
 	qlcnic_change_mtu(netdev, netdev->mtu);
 
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+		netdev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
 	netdev->hw_features |= NETIF_F_SG;
 	SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
 
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 9b7bddf..a0905de 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -683,8 +683,6 @@ const struct ethtool_ops qlge_ethtool_ops = {
 	.set_pauseparam		 = ql_set_pauseparam,
 	.get_rx_csum = ql_get_rx_csum,
 	.set_rx_csum = ql_set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.set_tx_csum = ethtool_op_set_tx_csum,
 	.get_coalesce = ql_get_coalesce,
 	.set_coalesce = ql_set_coalesce,
 	.get_sset_count = ql_get_sset_count,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index fb36da6..5b8a2bd 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -4713,6 +4713,7 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
 	ndev->irq = pdev->irq;
 
 	ndev->netdev_ops = &qlge_netdev_ops;
+	ndev->hw_features |= NETIF_F_IP_CSUM;
 	ndev->hw_features |= NETIF_F_SG;
 	ndev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 999a713..9f45f47 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1276,7 +1276,6 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
 	.set_msglevel		= rtl8169_set_msglevel,
 	.get_rx_csum		= rtl8169_get_rx_csum,
 	.set_rx_csum		= rtl8169_set_rx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum,
 	.get_regs		= rtl8169_get_regs,
 	.get_wol		= rtl8169_get_wol,
 	.set_wol		= rtl8169_set_wol,
@@ -3171,6 +3170,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
+	dev->hw_features |= NETIF_F_IP_CSUM;
 	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
 	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index ef63529..6eb63bc 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -6694,16 +6694,6 @@ static void s2io_ethtool_get_strings(struct net_device *dev,
 	}
 }
 
-static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= NETIF_F_IP_CSUM;
-	else
-		dev->features &= ~NETIF_F_IP_CSUM;
-
-	return 0;
-}
-
 static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
 {
 	struct s2io_nic *sp = netdev_priv(dev);
@@ -6751,7 +6741,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
 	.set_pauseparam = s2io_ethtool_setpause_data,
 	.get_rx_csum = s2io_ethtool_get_rx_csum,
 	.set_rx_csum = s2io_ethtool_set_rx_csum,
-	.set_tx_csum = s2io_ethtool_op_set_tx_csum,
 	.set_flags = s2io_ethtool_set_flags,
 	.get_flags = ethtool_op_get_flags,
 	.set_ufo = ethtool_op_set_ufo,
@@ -8016,7 +8005,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 
 	/*  Driver entry points */
 	dev->netdev_ops = &s2io_netdev_ops;
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_IP_CSUM;
 	dev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 26bb98b..f50737a 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1885,6 +1885,7 @@ static int efx_register_netdev(struct efx_nic *efx)
 	net_dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	if (efx->type->offload_features & NETIF_F_V6_CSUM)
 		net_dev->hw_features |= NETIF_F_TSO6;
+	net_dev->hw_features |= efx->type->offload_features & NETIF_F_ALL_CSUM;
 	SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
 
 	/* Clear MAC statistics */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index dd2b271..2ef2225 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -500,19 +500,6 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
 	}
 }
 
-static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
-{
-	struct efx_nic *efx = netdev_priv(net_dev);
-	unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM;
-
-	if (enable)
-		net_dev->features |= features;
-	else
-		net_dev->features &= ~features;
-
-	return 0;
-}
-
 static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
@@ -1110,9 +1097,6 @@ const struct ethtool_ops efx_ethtool_ops = {
 	.set_pauseparam         = efx_ethtool_set_pauseparam,
 	.get_rx_csum		= efx_ethtool_get_rx_csum,
 	.set_rx_csum		= efx_ethtool_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	/* Need to enable/disable IPv6 too */
-	.set_tx_csum		= efx_ethtool_set_tx_csum,
 	.get_flags		= ethtool_op_get_flags,
 	.set_flags		= efx_ethtool_set_flags,
 	.get_sset_count		= efx_ethtool_get_sset_count,
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index ac153bd..7cabfa2 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -537,17 +537,6 @@ static int skge_nway_reset(struct net_device *dev)
 	return 0;
 }
 
-static int skge_set_tx_csum(struct net_device *dev, u32 data)
-{
-	struct skge_port *skge = netdev_priv(dev);
-	struct skge_hw *hw = skge->hw;
-
-	if (hw->chip_id == CHIP_ID_GENESIS && data)
-		return -EOPNOTSUPP;
-
-	return ethtool_op_set_tx_csum(dev, data);
-}
-
 static u32 skge_get_rx_csum(struct net_device *dev)
 {
 	struct skge_port *skge = netdev_priv(dev);
@@ -915,7 +904,6 @@ static const struct ethtool_ops skge_ethtool_ops = {
 	.set_pauseparam = skge_set_pauseparam,
 	.get_coalesce	= skge_get_coalesce,
 	.set_coalesce	= skge_set_coalesce,
-	.set_tx_csum	= skge_set_tx_csum,
 	.get_rx_csum	= skge_get_rx_csum,
 	.set_rx_csum	= skge_set_rx_csum,
 	.get_strings	= skge_get_strings,
@@ -3801,7 +3789,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->netdev_ops = &skge_netdev_ops;
 	if (hw->chip_id != CHIP_ID_GENESIS)
-		dev->hw_features |= NETIF_F_SG;
+		dev->hw_features |= NETIF_F_SG|NETIF_F_IP_CSUM;
 	dev->ethtool_ops = &skge_ethtool_ops;
 	dev->watchdog_timeo = TX_WATCHDOG;
 	dev->irq = hw->pdev->irq;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 98534ef..2f8b615 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -4071,7 +4071,7 @@ static int sky2_set_tx_csum(struct net_device *dev, u32 data)
 	if (data && no_tx_offload(dev))
 		return -EINVAL;
 
-	return ethtool_op_set_tx_csum(dev, data);
+	return 0;
 }
 
 
@@ -4216,7 +4216,7 @@ static const struct ethtool_ops sky2_ethtool_ops = {
 	.get_eeprom_len	= sky2_get_eeprom_len,
 	.get_eeprom	= sky2_get_eeprom,
 	.set_eeprom	= sky2_set_eeprom,
-	.set_tx_csum	= sky2_set_tx_csum,
+	.hw_set_tx_csum	= sky2_set_tx_csum,
 	.hw_set_tso	= sky2_set_tso,
 	.get_rx_csum	= sky2_get_rx_csum,
 	.set_rx_csum	= sky2_set_rx_csum,
@@ -4549,6 +4549,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
 
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->irq = hw->pdev->irq;
+	dev->hw_features |= NETIF_F_IP_CSUM;
 	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops);
 	dev->watchdog_timeo = TX_WATCHDOG;
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index cb6bcca..2476ef5 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -2287,6 +2287,7 @@ spider_net_setup_netdev_ops(struct net_device *netdev)
 	netdev->netdev_ops = &spider_net_ops;
 	netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
 	/* ethtool ops */
+	netdev->hw_features |= NETIF_F_IP_CSUM;
 	netdev->ethtool_ops = &spider_net_ethtool_ops;
 }
 
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index 5bae728..912098d 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -191,7 +191,6 @@ const struct ethtool_ops spider_net_ethtool_ops = {
 	.nway_reset		= spider_net_ethtool_nway_reset,
 	.get_rx_csum		= spider_net_ethtool_get_rx_csum,
 	.set_rx_csum		= spider_net_ethtool_set_rx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum,
 	.get_ringparam          = spider_net_ethtool_get_ringparam,
 	.get_strings		= spider_net_get_strings,
 	.get_sset_count		= spider_net_get_sset_count,
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
index 0674ebb..285fdb6 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -197,16 +197,6 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
 	}
 }
 
-static int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data)
-{
-	if (data)
-		netdev->features |= NETIF_F_HW_CSUM;
-	else
-		netdev->features &= ~NETIF_F_HW_CSUM;
-
-	return 0;
-}
-
 static u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
@@ -369,8 +359,6 @@ static struct ethtool_ops stmmac_ethtool_ops = {
 	.get_regs_len = stmmac_ethtool_get_regs_len,
 	.get_link = ethtool_op_get_link,
 	.get_rx_csum = stmmac_ethtool_get_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.set_tx_csum = stmmac_ethtool_set_tx_csum,
 	.get_pauseparam = stmmac_get_pauseparam,
 	.set_pauseparam = stmmac_set_pauseparam,
 	.get_ethtool_stats = stmmac_get_ethtool_stats,
@@ -382,6 +370,7 @@ static struct ethtool_ops stmmac_ethtool_ops = {
 
 void stmmac_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops);
 }
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 42913bf..f4a7a33 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -2197,15 +2197,6 @@ static u32 bdx_get_rx_csum(struct net_device *netdev)
 }
 
 /*
- * bdx_get_tx_csum - report whether transmit checksums are turned on or off
- * @netdev
- */
-static u32 bdx_get_tx_csum(struct net_device *netdev)
-{
-	return (netdev->features & NETIF_F_IP_CSUM) != 0;
-}
-
-/*
  * bdx_get_coalesce - get interrupt coalescing parameters
  * @netdev
  * @ecoal
@@ -2425,7 +2416,6 @@ static void bdx_set_ethtool_ops(struct net_device *netdev)
 		.get_ringparam = bdx_get_ringparam,
 		.set_ringparam = bdx_set_ringparam,
 		.get_rx_csum = bdx_get_rx_csum,
-		.get_tx_csum = bdx_get_tx_csum,
 		.get_strings = bdx_get_strings,
 		.get_sset_count = bdx_get_sset_count,
 		.get_ethtool_stats = bdx_get_ethtool_stats,
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index c08172d..71ffc2e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -10249,24 +10249,6 @@ static int tg3_set_rx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static int tg3_set_tx_csum(struct net_device *dev, u32 data)
-{
-	struct tg3 *tp = netdev_priv(dev);
-
-	if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
-		if (data != 0)
-			return -EINVAL;
-		return 0;
-	}
-
-	if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
-		ethtool_op_set_tx_ipv6_csum(dev, data);
-	else
-		ethtool_op_set_tx_csum(dev, data);
-
-	return 0;
-}
-
 static int tg3_get_sset_count(struct net_device *dev, int sset)
 {
 	switch (sset) {
@@ -11306,7 +11288,6 @@ static const struct ethtool_ops tg3_ethtool_ops = {
 	.set_pauseparam		= tg3_set_pauseparam,
 	.get_rx_csum		= tg3_get_rx_csum,
 	.set_rx_csum		= tg3_set_rx_csum,
-	.set_tx_csum		= tg3_set_tx_csum,
 	.hw_set_tso		= tg3_set_tso,
 	.self_test		= tg3_self_test,
 	.get_strings		= tg3_get_strings,
@@ -14694,6 +14675,13 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 		goto err_out_iounmap;
 	}
 
+	if (!(tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS)) {
+		if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
+			dev->hw_features |= NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM;
+		else
+			dev->hw_features |= NETIF_F_IP_CSUM;
+	}
+
 	if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index cc2f811..0f83e9f 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1190,7 +1190,6 @@ static const struct ethtool_ops typhoon_ethtool_ops = {
 	.set_wol		= typhoon_set_wol,
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= typhoon_get_rx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum,
 	.get_ringparam		= typhoon_get_ringparam,
 	.set_flags		= typhoon_set_flags,
 	.get_flags		= ethtool_op_get_flags,
@@ -2478,6 +2477,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
 	dev->watchdog_timeo	= TX_TIMEOUT;
 
+	dev->hw_features |= NETIF_F_IP_CSUM;
 	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &typhoon_ethtool_ops);
 
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 466ed50..3373490 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -628,8 +628,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = {
 	.get_eeprom_len	= smsc75xx_ethtool_get_eeprom_len,
 	.get_eeprom	= smsc75xx_ethtool_get_eeprom,
 	.set_eeprom	= smsc75xx_ethtool_set_eeprom,
-	.get_tx_csum	= ethtool_op_get_tx_csum,
-	.set_tx_csum	= ethtool_op_set_tx_hw_csum,
 	.get_rx_csum	= smsc75xx_ethtool_get_rx_csum,
 	.set_rx_csum	= smsc75xx_ethtool_set_rx_csum,
 };
@@ -948,7 +946,6 @@ static int smsc75xx_reset(struct usbnet *dev)
 	netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl);
 
 	/* Enable or disable checksum offload engines */
-	ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE);
 	ret = smsc75xx_set_rx_csum_offload(dev);
 	check_warn_return(ret, "Failed to set rx csum offload: %d", ret);
 
@@ -1057,12 +1054,15 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
 	dev->net->features |= NETIF_F_SG;
 	if (DEFAULT_TSO_ENABLE)
 		dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6;
+	if (DEFAULT_TX_CSUM_ENABLE)
+		dev->net->features |= NETIF_F_HW_CSUM;
 
 	/* Init all registers */
 	ret = smsc75xx_reset(dev);
 
 	dev->net->netdev_ops = &smsc75xx_netdev_ops;
 	dev->net->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
+	dev->net->hw_features |= NETIF_F_HW_CSUM;
 	dev->net->ethtool_ops = &smsc75xx_ethtool_ops;
 	dev->net->flags |= IFF_MULTICAST;
 	dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD;
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 65cb1ab..09d0dbe 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -591,14 +591,6 @@ static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
 	return smsc95xx_set_csums(dev);
 }
 
-static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev)
-{
-	struct usbnet *dev = netdev_priv(netdev);
-	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
-	return pdata->use_tx_csum;
-}
-
 static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val)
 {
 	struct usbnet *dev = netdev_priv(netdev);
@@ -606,7 +598,6 @@ static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val)
 
 	pdata->use_tx_csum = !!val;
 
-	ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
 	return smsc95xx_set_csums(dev);
 }
 
@@ -621,8 +612,7 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = {
 	.get_eeprom_len	= smsc95xx_ethtool_get_eeprom_len,
 	.get_eeprom	= smsc95xx_ethtool_get_eeprom,
 	.set_eeprom	= smsc95xx_ethtool_set_eeprom,
-	.get_tx_csum	= smsc95xx_ethtool_get_tx_csum,
-	.set_tx_csum	= smsc95xx_ethtool_set_tx_csum,
+	.hw_set_tx_csum	= smsc95xx_ethtool_set_tx_csum,
 	.get_rx_csum	= smsc95xx_ethtool_get_rx_csum,
 	.set_rx_csum	= smsc95xx_ethtool_set_rx_csum,
 };
@@ -972,7 +962,8 @@ static int smsc95xx_reset(struct usbnet *dev)
 	}
 
 	/* Enable or disable checksum offload engines */
-	ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
+	if (pdata->use_tx_csum)
+		dev->net->features |= NETIF_F_HW_CSUM;
 	ret = smsc95xx_set_csums(dev);
 	if (ret < 0) {
 		netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret);
@@ -1051,6 +1042,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
 	ret = smsc95xx_reset(dev);
 
 	dev->net->netdev_ops = &smsc95xx_netdev_ops;
+	dev->net->hw_features = NETIF_F_HW_CSUM;
 	dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
 	dev->net->flags |= IFF_MULTICAST;
 	dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index d00db8a..72c278b 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -116,28 +116,12 @@ static int veth_set_rx_csum(struct net_device *dev, u32 data)
 	return 0;
 }
 
-static u32 veth_get_tx_csum(struct net_device *dev)
-{
-	return (dev->features & NETIF_F_NO_CSUM) != 0;
-}
-
-static int veth_set_tx_csum(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= NETIF_F_NO_CSUM;
-	else
-		dev->features &= ~NETIF_F_NO_CSUM;
-	return 0;
-}
-
 static const struct ethtool_ops veth_ethtool_ops = {
 	.get_settings		= veth_get_settings,
 	.get_drvinfo		= veth_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= veth_get_rx_csum,
 	.set_rx_csum		= veth_set_rx_csum,
-	.get_tx_csum		= veth_get_tx_csum,
-	.set_tx_csum		= veth_set_tx_csum,
 	.get_strings		= veth_get_strings,
 	.get_sset_count		= veth_get_sset_count,
 	.get_ethtool_stats	= veth_get_ethtool_stats,
@@ -297,7 +281,7 @@ static void veth_setup(struct net_device *dev)
 	ether_setup(dev);
 
 	dev->netdev_ops = &veth_netdev_ops;
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_NO_CSUM;
 	dev->ethtool_ops = &veth_ethtool_ops;
 	dev->features |= NETIF_F_LLTX;
 	dev->destructor = veth_dev_free;
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index a6389ef..4e817c2 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -2838,7 +2838,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
 
 	dev->irq = pdev->irq;
 	dev->netdev_ops = &velocity_netdev_ops;
-	dev->hw_features |= NETIF_F_SG;
+	dev->hw_features |= NETIF_F_SG|NETIF_F_IP_CSUM;
 	dev->ethtool_ops = &velocity_ethtool_ops;
 	netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
 
@@ -3449,8 +3449,6 @@ static const struct ethtool_ops velocity_ethtool_ops = {
 	.get_settings	=	velocity_get_settings,
 	.set_settings	=	velocity_set_settings,
 	.get_drvinfo	=	velocity_get_drvinfo,
-	.set_tx_csum	=	ethtool_op_set_tx_csum,
-	.get_tx_csum	=	ethtool_op_get_tx_csum,
 	.get_wol	=	velocity_ethtool_get_wol,
 	.set_wol	=	velocity_ethtool_set_wol,
 	.get_msglevel	=	velocity_get_msglevel,
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 037913f..c783b1e 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -711,9 +711,9 @@ static int virtnet_set_tx_csum(struct net_device *dev, u32 data)
 	struct virtio_device *vdev = vi->vdev;
 
 	if (data && !virtio_has_feature(vdev, VIRTIO_NET_F_CSUM))
-		return -ENOSYS;
+		return -EINVAL;
 
-	return ethtool_op_set_tx_hw_csum(dev, data);
+	return 0;
 }
 
 static void virtnet_set_rx_mode(struct net_device *dev)
@@ -817,7 +817,7 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
 }
 
 static const struct ethtool_ops virtnet_ethtool_ops = {
-	.set_tx_csum = virtnet_set_tx_csum,
+	.hw_set_tx_csum = virtnet_set_tx_csum,
 	.set_ufo = ethtool_op_set_ufo,
 	.get_link = ethtool_op_get_link,
 };
@@ -901,6 +901,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 	/* Set up network device as normal. */
 	dev->netdev_ops = &virtnet_netdev;
 	dev->features = NETIF_F_HIGHDMA;
+	dev->hw_features |= NETIF_F_HW_CSUM;
 	dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
 	SET_NETDEV_DEV(dev, &vdev->dev);
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index a43c5fb..1cdfe63 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -545,8 +545,6 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
 	.get_link          = ethtool_op_get_link,
 	.get_rx_csum       = vmxnet3_get_rx_csum,
 	.set_rx_csum       = vmxnet3_set_rx_csum,
-	.get_tx_csum       = ethtool_op_get_tx_csum,
-	.set_tx_csum       = ethtool_op_set_tx_hw_csum,
 	.get_strings       = vmxnet3_get_strings,
 	.get_flags	   = ethtool_op_get_flags,
 	.set_flags	   = vmxnet3_set_flags,
@@ -558,6 +556,7 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
 
 void vmxnet3_set_ethtool_ops(struct net_device *netdev)
 {
+	netdev->hw_features |= NETIF_F_HW_CSUM;
 	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &vmxnet3_ethtool_ops);
 }
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
index df9e500..2da14e3 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/vxge/vxge-ethtool.c
@@ -1120,8 +1120,6 @@ static const struct ethtool_ops vxge_ethtool_ops = {
 	.set_pauseparam		= vxge_ethtool_setpause_data,
 	.get_rx_csum		= vxge_get_rx_csum,
 	.set_rx_csum		= vxge_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
 	.get_strings		= vxge_ethtool_get_strings,
 	.phys_id		= vxge_ethtool_idnic,
 	.get_sset_count		= vxge_ethtool_get_sset_count,
@@ -1130,6 +1128,7 @@ static const struct ethtool_ops vxge_ethtool_ops = {
 
 void vxge_initialize_ethtool_ops(struct net_device *ndev)
 {
+	ndev->hw_features |= NETIF_F_HW_CSUM;
 	ndev->hw_features |= NETIF_F_SG;
 	ndev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6;
 	SET_ETHTOOL_OPS(ndev, &vxge_ethtool_ops);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 5715ba6..913d36f 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1178,6 +1178,7 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev
 	netif_napi_add(netdev, &np->napi, xennet_poll, 64);
 	netdev->features        = NETIF_F_IP_CSUM;
 
+	netdev->hw_features |= NETIF_F_IP_CSUM;
 	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
 	SET_NETDEV_DEV(netdev, &dev->dev);
@@ -1639,7 +1640,6 @@ static void netback_changed(struct xenbus_device *dev,
 
 static const struct ethtool_ops xennet_ethtool_ops =
 {
-	.set_tx_csum = ethtool_op_set_tx_csum,
 	.hw_set_sg = xennet_set_sg,
 	.hw_set_tso = xennet_set_tso,
 	.get_link = ethtool_op_get_link,
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index efd49c9..a9c403b 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3237,21 +3237,15 @@ static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data)
 {
 	struct qeth_card *card = dev->ml_priv;
 
-	if (data) {
-		if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
-			dev->features |= NETIF_F_IP_CSUM;
-		else
-			return -EPERM;
-	} else
-		dev->features &= ~NETIF_F_IP_CSUM;
+	if (data && !qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
+		return -EINVAL;
 
 	return 0;
 }
 
 static const struct ethtool_ops qeth_l3_ethtool_ops = {
 	.get_link = ethtool_op_get_link,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.set_tx_csum = qeth_l3_ethtool_set_tx_csum,
+	.hw_set_tx_csum = qeth_l3_ethtool_set_tx_csum,
 	.get_rx_csum = qeth_l3_ethtool_get_rx_csum,
 	.set_rx_csum = qeth_l3_ethtool_set_rx_csum,
 	.hw_set_tso  = qeth_l3_ethtool_set_tso,
@@ -3354,6 +3348,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
 	card->dev->ml_priv = card;
 	card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
 	card->dev->mtu = card->info.initial_mtu;
+	card->dev->hw_features |= NETIF_F_IP_CSUM;
 	card->dev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
 	SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops);
 	card->dev->features |=	NETIF_F_HW_VLAN_TX |
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 7ad58bf..8a11ffc 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -91,7 +91,6 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
 	.set_settings = cvm_oct_set_settings,
 	.nway_reset = cvm_oct_nway_reset,
 	.get_link = ethtool_op_get_link,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 };
 
 /**
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 0efb1c9..2270479 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -544,10 +544,6 @@ struct net_device;
 /* Some generic methods drivers may use in their ethtool_ops */
 u32 ethtool_op_get_link(struct net_device *dev);
 u32 ethtool_op_get_rx_csum(struct net_device *dev);
-u32 ethtool_op_get_tx_csum(struct net_device *dev);
-int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
-int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
-int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data);
 u32 ethtool_op_get_ufo(struct net_device *dev);
 int ethtool_op_set_ufo(struct net_device *dev, u32 data);
 u32 ethtool_op_get_flags(struct net_device *dev);
@@ -576,8 +572,7 @@ void ethtool_ntuple_flush(struct net_device *dev);
  * set_pauseparam: Set pause parameters
  * get_rx_csum: Report whether receive checksums are turned on or off
  * set_rx_csum: Turn receive checksum on or off
- * get_tx_csum: Report whether transmit checksums are turned on or off
- * set_tx_csum: Turn transmit checksums on or off
+ * hw_set_tx_csum: Turn transmit checksums on or off
  * hw_set_sg: Turn scatter-gather on or off
  * hw_set_tso: Turn TCP segmentation offload on or off
  * get_ufo: Report whether UDP fragmentation offload is enabled
@@ -640,8 +635,7 @@ struct ethtool_ops {
 				  struct ethtool_pauseparam*);
 	u32	(*get_rx_csum)(struct net_device *);
 	int	(*set_rx_csum)(struct net_device *, u32);
-	u32	(*get_tx_csum)(struct net_device *);
-	int	(*set_tx_csum)(struct net_device *, u32);
+	int	(*hw_set_tx_csum)(struct net_device *, u32);
 	int	(*hw_set_sg)(struct net_device *, u32);
 	int	(*hw_set_tso)(struct net_device *, u32);
 	void	(*self_test)(struct net_device *, struct ethtool_test *, u64 *);
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index dbda588..c7ce04e 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -209,7 +209,7 @@ static int br_set_tx_csum(struct net_device *dev, u32 data)
 		br->feature_mask &= ~NETIF_F_ALL_CSUM;
 
 	br_features_recompute(br);
-	return 0;
+	return 1;
 }
 
 static int br_set_flags(struct net_device *netdev, u32 data)
@@ -300,8 +300,7 @@ void br_netpoll_disable(struct net_bridge_port *p)
 static const struct ethtool_ops br_ethtool_ops = {
 	.get_drvinfo    = br_getinfo,
 	.get_link	= ethtool_op_get_link,
-	.get_tx_csum	= ethtool_op_get_tx_csum,
-	.set_tx_csum 	= br_set_tx_csum,
+	.hw_set_tx_csum	= br_set_tx_csum,
 	.hw_set_sg	= br_set_sg,
 	.hw_set_tso	= br_set_tso,
 	.get_ufo	= ethtool_op_get_ufo,
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 9b0e598..95e8b7a 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -40,44 +40,6 @@ u32 ethtool_op_get_rx_csum(struct net_device *dev)
 }
 EXPORT_SYMBOL(ethtool_op_get_rx_csum);
 
-u32 ethtool_op_get_tx_csum(struct net_device *dev)
-{
-	return (dev->features & NETIF_F_ALL_CSUM) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_tx_csum);
-
-int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= NETIF_F_IP_CSUM;
-	else
-		dev->features &= ~NETIF_F_IP_CSUM;
-
-	return 0;
-}
-
-int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= NETIF_F_HW_CSUM;
-	else
-		dev->features &= ~NETIF_F_HW_CSUM;
-
-	return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
-
-int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
-{
-	if (data)
-		dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-	else
-		dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-
-	return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
-
 u32 ethtool_op_get_ufo(struct net_device *dev)
 {
 	return (dev->features & NETIF_F_UFO) != 0;
@@ -1077,12 +1039,18 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
 	return 0;
 }
 
+static u32 ethtool_get_tx_csum(struct net_device *dev)
+{
+	return (dev->features & (NETIF_F_ALL_CSUM|NETIF_F_SCTP_CSUM)) != 0;
+}
+
 static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
 {
+	unsigned long mask = dev->hw_features & (NETIF_F_ALL_CSUM|NETIF_F_SCTP_CSUM);
 	struct ethtool_value edata;
 	int err;
 
-	if (!dev->ethtool_ops->set_tx_csum)
+	if (!mask)
 		return -EOPNOTSUPP;
 
 	if (copy_from_user(&edata, useraddr, sizeof(edata)))
@@ -1094,9 +1062,19 @@ static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
 			return err;
 	}
 
-	return dev->ethtool_ops->set_tx_csum(dev, edata.data);
+	if (dev->ethtool_ops->hw_set_tx_csum) {
+		err = dev->ethtool_ops->hw_set_tx_csum(dev, edata.data);
+		if (err)
+			return min(err, 0);
+	}
+
+	if (edata.data)
+		dev->features |= mask;
+	else
+		dev->features &= ~mask;
+
+	return 0;
 }
-EXPORT_SYMBOL(ethtool_op_set_tx_csum);
 
 static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr)
 {
@@ -1568,9 +1546,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 		break;
 	case ETHTOOL_GTXCSUM:
 		rc = ethtool_get_value(dev, useraddr, ethcmd,
-				       (dev->ethtool_ops->get_tx_csum ?
-					dev->ethtool_ops->get_tx_csum :
-					ethtool_op_get_tx_csum));
+					ethtool_get_tx_csum);
 		break;
 	case ETHTOOL_STXCSUM:
 		rc = ethtool_set_tx_csum(dev, useraddr);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 0/4] Ethtool: cleanup strategy
@ 2010-10-31  3:40 Michał Mirosław
  2010-10-30  4:27 ` [PATCH 1/4] Ethtool: Introduce hw_features field in struct netdevice Michał Mirosław
                   ` (5 more replies)
  0 siblings, 6 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-10-31  3:40 UTC (permalink / raw)
  To: netdev
  Cc: e1000-devel, Steve Glendinning, Greg Kroah-Hartman, Rasesh Mody,
	Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

While writing and debugging driver for StorLink's Gemini ethernet
"card" I couldn't not notice that ethtool support had accumulated a lot
of dust and "aah, let's just copy that from another driver"-generated
code.  There are things that are reimplemented in more-or-less same way
in multiple network drivers, there are logic bugs or unexpected
variations among the implementations, and there is a lot of boilerplate
code needed to be written by a person who wants to support ethtool
in his driver.  I'm concentrating on offload feature setting here as
that's what I needed for my driver.

As I scanned through multiple drivers and ethtool core I noticed that
most (if not all) offload capabilities are determinable at ndo_init()
time.  There are, however, some exceptions as bridge and VLAN drivers,
or chips that have offload capabilities dependent on MTU setting.

Transmit offload features are the simple ones --- almost all drivers
enable support for them at per-packet when-needed basis and so they can
be disabled just by performing the required actions in software before
ndo_start_xmit(). Using a particular offload is mostly a matter of
setting its bit in netdev->features.

Receive offloads are another beast.  They usually need to be enabled
in hardware or ignored/worked-around by the driver for buggy HW.
Changing the offload's state is done in device-specific way.

My proposal is to implement a offload feature setting that needs
(almost) no code in network driver.  The idea is to add two
ethtool-specific fields to struct net_device:

 - hw_features
      offloads supported by the netdev (togglable by user)
 - features_requested
      offloads currently requested by user; this will be superset of
      (features & hw_features) when i.e. current MTU or other external
      conditions disable some offloads

... and use them to implement changing of offloads in ethtool core.
Since get_*() for TX offloads is just a bit test on netdev->features,
corresponding ethtool entry points could be removed.

This patch series is a beginning proof-of-concept work for this idea.
This is a minimal cleanup and move of TX checksum, scatter-gather and
TSO offloads to the new arrangement.  This is intended to be a mostly
no-op in functionality, so most bugs there are preserved and only
minimal code changes in drivers are made except when driver-local
get/set function code can be removed.

Please apply it if you like it as it is now. Further changes will
depend on those anyway. Later in this mail I attached couple of notes
I've taken during the conversion of some drivers. As the Cc list for
all maintainers would be huge (all network drivers are touched), I kept
only those who's drivers are changed in less obvious or uncertain ways.

Best Regards,
Michał Mirosław


  loopback
	missing TSO6 in netdev->features

  bridge
	dynamic hw caps - might need more thought

  8021q/vlan
	uses set_tso, missing TSO6 in tested features
	dynamic hw caps -> might need more thought

  xen-netfront
	optimize offload setting

  ipoib
	uses set_tso - can be moved to netdev_init?

* cxgb2
	assumed: adapter->flags initialized and can't change

* e1000
	removed unused adapter->tso_force
	set_tx_csum side-effect: fix inverted test

  enic
	uses set_tso - can be moved to netdev_init?

* ixgbevf
	set_tso: netif_tx_stop/start_all_queues removed from disable path

  jme
	csum,tso limited to MTU <= 1900

  mlx4
	uses set_tso - can be moved to netdev_init?
		errno: EPERM -> EINVAL

  tg3
	uses set_tso - parts can be moved to netdev_init?
		tso MTU 1500 on some boards
	TG3_FLAG_BROKEN_CHECKSUMS - are netdev->features based on this?

* usb/smsc75xx
	set tx_csum,tso features reset() -> init() - ok?

* usb/smsc95xx
	uses set_tx_csum
	move features change from reset()? - ok to set like this if not?

* bna
	set_tx_csum: removed bnad->conf_mutex locking

  dm9000
	removed struct board_info->can_csum

* gianfar
	set_tx_csum: removed netif_tx_lock_bh() locking

* greth
	set_tx_csum: removed netif_tx_lock_bh() locking

  ibmveth
	uses set_tx_csum - can be changed to avoid it?

  pch_gbe
	uses set_tx_csum - remove adapter->tx_csum completely?
		it's redundant (== netdev->features & NETIF_F_HW_CSUM)

* qlcnic
	set_tx_csum: is ESWITCH exclusion constant?

* sfc
	assumed: constant efx->type->offload_features

  sky2
	set_tx_csum, set_tso: merge to no_tx_offload()?
		MTU 1500 for CHIP_ID_YUKON_EC_U

  s390/net
	uses set_tso
	uses set_tx_csum - can be moved to netdev_init?



Michał Mirosław (4):
  Ethtool: Introduce hw_features field in struct netdevice
  Ethtool: convert get_sg/set_sg calls to hw_features flag
  Ethtool: convert get_tso/set_tso calls to hw_features flags
  Ethtool: convert get_tx_csum/set_tx_csum calls to hw_features flags

 drivers/infiniband/hw/nes/nes_nic.c          |    8 +-
 drivers/infiniband/ulp/ipoib/ipoib_ethtool.c |   10 +-
 drivers/net/8139cp.c                         |    5 +-
 drivers/net/atl1c/atl1c_ethtool.c            |    9 +--
 drivers/net/atl1e/atl1e_ethtool.c            |    5 +-
 drivers/net/atlx/atl1.c                      |    6 +-
 drivers/net/atlx/atl2.c                      |   12 +--
 drivers/net/benet/be_ethtool.c               |    6 -
 drivers/net/benet/be_main.c                  |    2 +
 drivers/net/bna/bnad_ethtool.c               |   43 +-------
 drivers/net/bnx2.c                           |   33 +-----
 drivers/net/bnx2x/bnx2x_ethtool.c            |   21 +---
 drivers/net/bonding/bond_main.c              |    3 -
 drivers/net/chelsio/cxgb2.c                  |   15 +--
 drivers/net/cxgb3/cxgb3_main.c               |    5 +-
 drivers/net/cxgb4/cxgb4_main.c               |   14 +--
 drivers/net/cxgb4vf/cxgb4vf_main.c           |   18 +---
 drivers/net/dm9000.c                         |   17 +---
 drivers/net/e1000/e1000.h                    |    1 -
 drivers/net/e1000/e1000_ethtool.c            |   58 ++--------
 drivers/net/e1000e/ethtool.c                 |   32 +-----
 drivers/net/ehea/ehea_ethtool.c              |    2 +-
 drivers/net/enic/enic_main.c                 |   23 +---
 drivers/net/forcedeth.c                      |   35 +-----
 drivers/net/fs_enet/fs_enet-main.c           |    3 +-
 drivers/net/gianfar.c                        |    2 +
 drivers/net/gianfar_ethtool.c                |   32 -----
 drivers/net/greth.c                          |   16 +---
 drivers/net/ibm_newemac/core.c               |    2 -
 drivers/net/ibmveth.c                        |    6 +-
 drivers/net/igb/igb_ethtool.c                |   51 +-------
 drivers/net/igbvf/ethtool.c                  |   40 +------
 drivers/net/ioc3-eth.c                       |    3 +-
 drivers/net/ixgb/ixgb_ethtool.c              |   33 +-----
 drivers/net/ixgbe/ixgbe_ethtool.c            |   48 ++-------
 drivers/net/ixgbevf/ethtool.c                |   23 +---
 drivers/net/jme.c                            |   17 ++--
 drivers/net/ksz884x.c                        |    6 +-
 drivers/net/loopback.c                       |    4 +-
 drivers/net/mlx4/en_ethtool.c                |   23 +---
 drivers/net/mlx4/en_netdev.c                 |    3 +
 drivers/net/mv643xx_eth.c                    |    3 +-
 drivers/net/myri10ge/myri10ge.c              |   17 +---
 drivers/net/netxen/netxen_nic_ethtool.c      |   34 ------
 drivers/net/netxen/netxen_nic_main.c         |    4 +
 drivers/net/pch_gbe/pch_gbe_ethtool.c        |   20 +---
 drivers/net/ps3_gelic_net.c                  |    3 +-
 drivers/net/ps3_gelic_wireless.c             |    3 +-
 drivers/net/qlcnic/qlcnic_ethtool.c          |   42 -------
 drivers/net/qlcnic/qlcnic_main.c             |    4 +
 drivers/net/qlge/qlge_ethtool.c              |   19 ---
 drivers/net/qlge/qlge_main.c                 |    3 +
 drivers/net/r8169.c                          |    5 +-
 drivers/net/s2io.c                           |   31 +-----
 drivers/net/sfc/efx.c                        |    4 +
 drivers/net/sfc/ethtool.c                    |   38 ------
 drivers/net/skge.c                           |   25 +----
 drivers/net/sky2.c                           |   11 +-
 drivers/net/spider_net.c                     |    1 +
 drivers/net/spider_net_ethtool.c             |    1 -
 drivers/net/stmmac/stmmac_ethtool.c          |   18 +---
 drivers/net/tehuti.c                         |   12 --
 drivers/net/tg3.c                            |   66 +++++------
 drivers/net/typhoon.c                        |    5 +-
 drivers/net/ucc_geth_ethtool.c               |    2 +-
 drivers/net/usb/smsc75xx.c                   |   23 +---
 drivers/net/usb/smsc95xx.c                   |   16 +--
 drivers/net/veth.c                           |   19 +---
 drivers/net/via-velocity.c                   |    4 +-
 drivers/net/virtio_net.c                     |   10 +-
 drivers/net/vmxnet3/vmxnet3_ethtool.c        |    8 +-
 drivers/net/vxge/vxge-ethtool.c              |   19 +---
 drivers/net/xen-netfront.c                   |   19 ++-
 drivers/s390/net/qeth_l3_main.c              |   21 +---
 drivers/staging/hv/netvsc_drv.c              |    3 +-
 drivers/staging/octeon/ethernet-mdio.c       |    2 -
 include/linux/ethtool.h                      |   26 +---
 include/linux/netdevice.h                    |    4 +
 net/8021q/vlan_dev.c                         |    5 +-
 net/bridge/br_device.c                       |   16 +--
 net/core/ethtool.c                           |  162 +++++++++++---------------
 net/dsa/slave.c                              |    2 +-
 82 files changed, 307 insertions(+), 1118 deletions(-)


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 0/4] Ethtool: cleanup strategy
  2010-10-31  3:40 [PATCH 0/4] Ethtool: cleanup strategy Michał Mirosław
                   ` (3 preceding siblings ...)
  2010-10-31  0:09 ` [PATCH 4/4] Ethtool: convert get_tx_csum/set_tx_csum " Michał Mirosław
@ 2010-10-31  4:18 ` David Miller
  2010-10-31  4:30   ` Michał Mirosław
  2010-11-01 21:05 ` Ben Hutchings
  5 siblings, 1 reply; 22+ messages in thread
From: David Miller @ 2010-10-31  4:18 UTC (permalink / raw)
  To: mirq-linux
  Cc: linux-net-drivers, ddutt, e1000-devel, netdev, gregkh, rmody,
	linux-driver, steve.glendinning, kristoffer


Can you do me a huge favor?

In the future make the dates more sensible in your patch postings.

With how you did this, your patches are scattered all over the place
in patchwork because it orders things by date, have a look:

http://patchwork.ozlabs.org/project/netdev/list/

Thanks.

------------------------------------------------------------------------------
Nokia and AT&T present the 2010 Calling All Innovators-North America contest
Create new apps & games for the Nokia N8 for consumers in  U.S. and Canada
$10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing
Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store 
http://p.sf.net/sfu/nokia-dev2dev
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 0/4] Ethtool: cleanup strategy
  2010-10-31  4:18 ` [PATCH 0/4] Ethtool: cleanup strategy David Miller
@ 2010-10-31  4:30   ` Michał Mirosław
  0 siblings, 0 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-10-31  4:30 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

On Sat, Oct 30, 2010 at 09:18:20PM -0700, David Miller wrote:
> Can you do me a huge favor?
> 
> In the future make the dates more sensible in your patch postings.
> 
> With how you did this, your patches are scattered all over the place
> in patchwork because it orders things by date, have a look:
> 
> http://patchwork.ozlabs.org/project/netdev/list/

Thanks for the hint.  I used git format-patch and it creates Date
headers based on git commit time.  I'll probably just filter them
or git rebase before sending patches from now on.

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 0/4] Ethtool: cleanup strategy
  2010-10-31  3:40 [PATCH 0/4] Ethtool: cleanup strategy Michał Mirosław
                   ` (4 preceding siblings ...)
  2010-10-31  4:18 ` [PATCH 0/4] Ethtool: cleanup strategy David Miller
@ 2010-11-01 21:05 ` Ben Hutchings
  2010-11-02  1:02   ` Michał Mirosław
  5 siblings, 1 reply; 22+ messages in thread
From: Ben Hutchings @ 2010-11-01 21:05 UTC (permalink / raw)
  To: Michał Mirosław
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Sun, 2010-10-31 at 04:40 +0100, Michał Mirosław wrote:
> While writing and debugging driver for StorLink's Gemini ethernet
> "card" I couldn't not notice that ethtool support had accumulated a lot
> of dust and "aah, let's just copy that from another driver"-generated
> code.  There are things that are reimplemented in more-or-less same way
> in multiple network drivers, there are logic bugs or unexpected
> variations among the implementations, and there is a lot of boilerplate
> code needed to be written by a person who wants to support ethtool
> in his driver.  I'm concentrating on offload feature setting here as
> that's what I needed for my driver.

I agree; I've fixed a few of these variations but I'm aware there are
many left.  Thanks for taking on some of this cleanup work.

[...]
> My proposal is to implement a offload feature setting that needs
> (almost) no code in network driver.  The idea is to add two
> ethtool-specific fields to struct net_device:
> 
>  - hw_features
>       offloads supported by the netdev (togglable by user)
>  - features_requested
>       offloads currently requested by user; this will be superset of
>       (features & hw_features) when i.e. current MTU or other external
>       conditions disable some offloads
> 
> ... and use them to implement changing of offloads in ethtool core.
> Since get_*() for TX offloads is just a bit test on netdev->features,
> corresponding ethtool entry points could be removed.

Right.

It also might be worth defining a standard feature flag for RX checksum
offload, since currently every driver has to maintain its own private
flag.  Though we're running short of feature flags on 32-bit machines.

[...]
> * sfc
> 	assumed: constant efx->type->offload_features
[...]

This is correct.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag
  2010-10-30  4:28 ` [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag Michał Mirosław
@ 2010-11-01 21:15   ` Ben Hutchings
  2010-11-02  0:59     ` Michał Mirosław
  2010-11-02  2:24   ` Matt Carlson
  1 sibling, 1 reply; 22+ messages in thread
From: Ben Hutchings @ 2010-11-01 21:15 UTC (permalink / raw)
  To: Michał Mirosław
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Sat, 2010-10-30 at 06:28 +0200, Michał Mirosław wrote:
[...]
> @@ -1088,7 +1076,19 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
>  		if (err)
>  			return err;
>  	}
> -	return dev->ethtool_ops->set_sg(dev, data);
> +
> +	if (dev->ethtool_ops->hw_set_sg) {
> +		err = dev->ethtool_ops->hw_set_sg(dev, data);
> +		if (err)
> +			return min(err, 0);
> +	}
> +
> +	if (data)
> +		dev->features |= NETIF_F_SG;
> +	else
> +		dev->features &= ~NETIF_F_SG;
> +
> +	return 0;
>  }
[...]

The odd semantics of positive return values really need to be documented
- both in the commit message and in the comment on struct ethtool_ops.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags
  2010-10-30  8:44 ` [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags Michał Mirosław
@ 2010-11-01 21:25   ` Ben Hutchings
  2010-11-02  1:14     ` Michał Mirosław
  2010-11-02  2:49   ` Matt Carlson
  1 sibling, 1 reply; 22+ messages in thread
From: Ben Hutchings @ 2010-11-01 21:25 UTC (permalink / raw)
  To: Michał Mirosław
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Sat, 2010-10-30 at 10:44 +0200, Michał Mirosław wrote:
[...]
> @@ -1670,7 +1668,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
>  	netdev->type = ARPHRD_ETHER;
>  	netdev->features = NETIF_F_HIGHDMA;
>  	netdev->netdev_ops = &nes_netdev_ops;
> -	netdev->hw_features |= NETIF_F_SG;
> +	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;

There should be spaces on either side of the '|' operator.

[...]
> diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
> index 9e27bd6..814a06c 100644
> --- a/drivers/net/atlx/atl1.c
> +++ b/drivers/net/atlx/atl1.c
> @@ -2992,6 +2992,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
>  	netdev->watchdog_timeo = 5 * HZ;
>  
>  	netdev->hw_features |= NETIF_F_SG;
> +	netdev->hw_features |= NETIF_F_TSO;

Why not set both flags in the same statement?  You might as well make
the drivers consistent in this regard.

[...]
> diff --git a/net/core/ethtool.c b/net/core/ethtool.c
> index 017667c..9b0e598 100644
> --- a/net/core/ethtool.c
> +++ b/net/core/ethtool.c
[...]
> @@ -1065,10 +1048,13 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
>  {
>  	int err;
>  
> -	if (!data && dev->ethtool_ops->set_tso) {
> -		err = dev->ethtool_ops->set_tso(dev, 0);
> -		if (err)
> -			return err;
> +	if (!data && (dev->hw_features & NETIF_F_ALL_TSO)) {
> +		if (dev->ethtool_ops->hw_set_tso) {
> +			err = dev->ethtool_ops->hw_set_tso(dev, 0);
> +			if (err < 0)
> +				return err;
> +		}
> +		dev->features &= dev->hw_features & NETIF_F_ALL_TSO;

Surely this should be:
		dev->features &= ~NETIF_F_ALL_TSO;

[...]
> @@ -1158,7 +1149,18 @@ static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
>  	if (edata.data && !(dev->features & NETIF_F_SG))
>  		return -EINVAL;
>  
> -	return dev->ethtool_ops->set_tso(dev, edata.data);
> +	if (dev->ethtool_ops->hw_set_tso) {
> +		int err = dev->ethtool_ops->hw_set_tso(dev, edata.data);
> +		if (err)
> +			return min(err, 0);
[...]

Again, the odd semantics of a positive value need to be documented.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 4/4] Ethtool: convert get_tx_csum/set_tx_csum calls to hw_features flags
  2010-10-31  0:09 ` [PATCH 4/4] Ethtool: convert get_tx_csum/set_tx_csum " Michał Mirosław
@ 2010-11-01 21:38   ` Ben Hutchings
  2010-11-02  1:23     ` Michał Mirosław
  0 siblings, 1 reply; 22+ messages in thread
From: Ben Hutchings @ 2010-11-01 21:38 UTC (permalink / raw)
  To: Michał Mirosław
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Sun, 2010-10-31 at 02:09 +0200, Michał Mirosław wrote:
[...]
> diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
> index 9f6aeef..5ba4535 100644
> --- a/drivers/net/dm9000.c
> +++ b/drivers/net/dm9000.c
> @@ -132,7 +132,6 @@ typedef struct board_info {
>  	u32		wake_state;
>  
>  	int		rx_csum;
> -	int		can_csum;
>  	int		ip_summed;
>  } board_info_t;
>  
> @@ -480,7 +479,7 @@ static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data)
>  {
>  	board_info_t *dm = to_dm9000_board(dev);
>  
> -	if (dm->can_csum) {
> +	if (dev->hw_features & NETIF_F_IP_CSUM) {

This is a bit ugly because can_csum is being used to indicate RX
checksum offload capability whereas the checksum feature flags logically
indicate TX checksum offload capability.  Of course, the two hardware
features are highly correlated!

[...]
> diff --git a/net/core/ethtool.c b/net/core/ethtool.c
> index 9b0e598..95e8b7a 100644
> --- a/net/core/ethtool.c
> +++ b/net/core/ethtool.c
[...]
> @@ -1077,12 +1039,18 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
>  	return 0;
>  }
>  
> +static u32 ethtool_get_tx_csum(struct net_device *dev)
> +{
> +	return (dev->features & (NETIF_F_ALL_CSUM|NETIF_F_SCTP_CSUM)) != 0;
> +}
> +
[...]

It seems to me that NETIF_F_SCTP_CSUM should be added to
NETIF_F_ALL_CSUM, though that may cause problems in some other places
NETIF_F_ALL_CSUM is used.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag
  2010-11-01 21:15   ` Ben Hutchings
@ 2010-11-02  0:59     ` Michał Mirosław
  0 siblings, 0 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-11-02  0:59 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Mon, Nov 01, 2010 at 09:15:50PM +0000, Ben Hutchings wrote:
> On Sat, 2010-10-30 at 06:28 +0200, Michał Mirosław wrote:
> [...]
> > @@ -1088,7 +1076,19 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
> >  		if (err)
> >  			return err;
> >  	}
> > -	return dev->ethtool_ops->set_sg(dev, data);
> > +
> > +	if (dev->ethtool_ops->hw_set_sg) {
> > +		err = dev->ethtool_ops->hw_set_sg(dev, data);
> > +		if (err)
> > +			return min(err, 0);
> > +	}
> > +
> > +	if (data)
> > +		dev->features |= NETIF_F_SG;
> > +	else
> > +		dev->features &= ~NETIF_F_SG;
> > +
> > +	return 0;
> >  }
> [...]
> 
> The odd semantics of positive return values really need to be documented
> - both in the commit message and in the comment on struct ethtool_ops.

Will do.

Best Regards,
Michał Mirosław 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 0/4] Ethtool: cleanup strategy
  2010-11-01 21:05 ` Ben Hutchings
@ 2010-11-02  1:02   ` Michał Mirosław
  2010-11-02  1:14     ` Ben Hutchings
  0 siblings, 1 reply; 22+ messages in thread
From: Michał Mirosław @ 2010-11-02  1:02 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Mon, Nov 01, 2010 at 09:05:25PM +0000, Ben Hutchings wrote:
> [...]
> > My proposal is to implement a offload feature setting that needs
> > (almost) no code in network driver.  The idea is to add two
> > ethtool-specific fields to struct net_device:
> > 
> >  - hw_features
> >       offloads supported by the netdev (togglable by user)
> >  - features_requested
> >       offloads currently requested by user; this will be superset of
> >       (features & hw_features) when i.e. current MTU or other external
> >       conditions disable some offloads
> > 
> > ... and use them to implement changing of offloads in ethtool core.
> > Since get_*() for TX offloads is just a bit test on netdev->features,
> > corresponding ethtool entry points could be removed.
> 
> Right.
> 
> It also might be worth defining a standard feature flag for RX checksum
> offload, since currently every driver has to maintain its own private
> flag.  Though we're running short of feature flags on 32-bit machines.

RX offloads are different in that most devices allow readback of
configured bits, so actually no specific flags are needed. I've postponed
thinking about this until after I cleaning up TX part.

> [...]
> > * sfc
> > 	assumed: constant efx->type->offload_features
> [...]
> 
> This is correct.

Thanks,
Michał Mirosław


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 0/4] Ethtool: cleanup strategy
  2010-11-02  1:02   ` Michał Mirosław
@ 2010-11-02  1:14     ` Ben Hutchings
  2010-11-02  1:30       ` Michał Mirosław
  0 siblings, 1 reply; 22+ messages in thread
From: Ben Hutchings @ 2010-11-02  1:14 UTC (permalink / raw)
  To: Michał Mirosław
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

Michał Mirosław wrote:
> On Mon, Nov 01, 2010 at 09:05:25PM +0000, Ben Hutchings wrote:
[...]
> > It also might be worth defining a standard feature flag for RX checksum
> > offload, since currently every driver has to maintain its own private
> > flag.  Though we're running short of feature flags on 32-bit machines.
> 
> RX offloads are different in that most devices allow readback of
> configured bits, so actually no specific flags are needed.
[...]

Most devices also need resetting from time to time, so those flags still
need to be included in software state.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags
  2010-11-01 21:25   ` Ben Hutchings
@ 2010-11-02  1:14     ` Michał Mirosław
  0 siblings, 0 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-11-02  1:14 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Mon, Nov 01, 2010 at 09:25:54PM +0000, Ben Hutchings wrote:
> On Sat, 2010-10-30 at 10:44 +0200, Michał Mirosław wrote:
> [...]
> > @@ -1670,7 +1668,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
> >  	netdev->type = ARPHRD_ETHER;
> >  	netdev->features = NETIF_F_HIGHDMA;
> >  	netdev->netdev_ops = &nes_netdev_ops;
> > -	netdev->hw_features |= NETIF_F_SG;
> > +	netdev->hw_features |= NETIF_F_SG|NETIF_F_TSO;
> 
> There should be spaces on either side of the '|' operator.

The style varies among drivers' sources. I don't have any preference
whatsoever.

> [...]
> > diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
> > index 9e27bd6..814a06c 100644
> > --- a/drivers/net/atlx/atl1.c
> > +++ b/drivers/net/atlx/atl1.c
> > @@ -2992,6 +2992,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
> >  	netdev->watchdog_timeo = 5 * HZ;
> >  
> >  	netdev->hw_features |= NETIF_F_SG;
> > +	netdev->hw_features |= NETIF_F_TSO;
> 
> Why not set both flags in the same statement?  You might as well make
> the drivers consistent in this regard.

Will fix. The compiler should combine those anyway.

> [...]
> > diff --git a/net/core/ethtool.c b/net/core/ethtool.c
> > index 017667c..9b0e598 100644
> > --- a/net/core/ethtool.c
> > +++ b/net/core/ethtool.c
> [...]
> > @@ -1065,10 +1048,13 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
> >  {
> >  	int err;
> >  
> > -	if (!data && dev->ethtool_ops->set_tso) {
> > -		err = dev->ethtool_ops->set_tso(dev, 0);
> > -		if (err)
> > -			return err;
> > +	if (!data && (dev->hw_features & NETIF_F_ALL_TSO)) {
> > +		if (dev->ethtool_ops->hw_set_tso) {
> > +			err = dev->ethtool_ops->hw_set_tso(dev, 0);
> > +			if (err < 0)
> > +				return err;
> > +		}
> > +		dev->features &= dev->hw_features & NETIF_F_ALL_TSO;
> 
> Surely this should be:
> 		dev->features &= ~NETIF_F_ALL_TSO;

I originally thought of hw_features as a bitfield of features changable
by ethtool.  So if driver writer wanted to have TSO permanently on but
allow toggling of TSO6 for debug than that would work.  There is actually
a bug in original code: it doesn't clear NETIF_F_TSO if there is no set_tso
function, but clears NETIF_F_SG anyway (the bug is preserved).  This is
a material for successive patches.

BTW, why is scatter-gather needed for TSO and TX checksumming?  I see
no interdependence on s-g for those offloads.

> [...]
> > @@ -1158,7 +1149,18 @@ static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
> >  	if (edata.data && !(dev->features & NETIF_F_SG))
> >  		return -EINVAL;
> >  
> > -	return dev->ethtool_ops->set_tso(dev, edata.data);
> > +	if (dev->ethtool_ops->hw_set_tso) {
> > +		int err = dev->ethtool_ops->hw_set_tso(dev, edata.data);
> > +		if (err)
> > +			return min(err, 0);
> [...]
> 
> Again, the odd semantics of a positive value need to be documented.

Of course.

Best Regards,
Michał Mirosław
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 4/4] Ethtool: convert get_tx_csum/set_tx_csum calls to hw_features flags
  2010-11-01 21:38   ` Ben Hutchings
@ 2010-11-02  1:23     ` Michał Mirosław
  0 siblings, 0 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-11-02  1:23 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Mon, Nov 01, 2010 at 09:38:57PM +0000, Ben Hutchings wrote:
> On Sun, 2010-10-31 at 02:09 +0200, Michał Mirosław wrote:
> [...]
> > diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
> > index 9f6aeef..5ba4535 100644
> > --- a/drivers/net/dm9000.c
> > +++ b/drivers/net/dm9000.c
> > @@ -132,7 +132,6 @@ typedef struct board_info {
> >  	u32		wake_state;
> >  
> >  	int		rx_csum;
> > -	int		can_csum;
> >  	int		ip_summed;
> >  } board_info_t;
> >  
> > @@ -480,7 +479,7 @@ static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data)
> >  {
> >  	board_info_t *dm = to_dm9000_board(dev);
> >  
> > -	if (dm->can_csum) {
> > +	if (dev->hw_features & NETIF_F_IP_CSUM) {
> 
> This is a bit ugly because can_csum is being used to indicate RX
> checksum offload capability whereas the checksum feature flags logically
> indicate TX checksum offload capability.  Of course, the two hardware
> features are highly correlated!

I briefly looked over the code. can_csum looked like "can do both TX
and RX checksum", so (dev->hw_features & NETIF_F_IP_CSUM) duplicates
information in this case. I can remove this change or just add a comment
that we abuse hw_features a bit.

> [...]
> > diff --git a/net/core/ethtool.c b/net/core/ethtool.c
> > index 9b0e598..95e8b7a 100644
> > --- a/net/core/ethtool.c
> > +++ b/net/core/ethtool.c
> [...]
> > @@ -1077,12 +1039,18 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
> >  	return 0;
> >  }
> >  
> > +static u32 ethtool_get_tx_csum(struct net_device *dev)
> > +{
> > +	return (dev->features & (NETIF_F_ALL_CSUM|NETIF_F_SCTP_CSUM)) != 0;
> > +}
> > +
> [...]
> 
> It seems to me that NETIF_F_SCTP_CSUM should be added to
> NETIF_F_ALL_CSUM, though that may cause problems in some other places
> NETIF_F_ALL_CSUM is used.

This would need auditing NETIF_F_ALL_CSUM usage across the kernel, so
definitely a further patch material.

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 0/4] Ethtool: cleanup strategy
  2010-11-02  1:14     ` Ben Hutchings
@ 2010-11-02  1:30       ` Michał Mirosław
  0 siblings, 0 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-11-02  1:30 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Tue, Nov 02, 2010 at 01:14:23AM +0000, Ben Hutchings wrote:
> Michał Mirosław wrote:
> > On Mon, Nov 01, 2010 at 09:05:25PM +0000, Ben Hutchings wrote:
> [...]
> > > It also might be worth defining a standard feature flag for RX checksum
> > > offload, since currently every driver has to maintain its own private
> > > flag.  Though we're running short of feature flags on 32-bit machines.
> > RX offloads are different in that most devices allow readback of
> > configured bits, so actually no specific flags are needed.
> [...]
> Most devices also need resetting from time to time, so those flags still
> need to be included in software state.

Ah. Good point. So this should be converted to the same way the TX offloads
will be handled.

Is it worth to split rx and tx features to separate bitfields?  Especially
that we're running out of bits in u32 and that TX flags are used in hot
path and RX are normally not accessed much.

Are the features flags exported somewhere to userspace except via ethtool?

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag
  2010-10-30  4:28 ` [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag Michał Mirosław
  2010-11-01 21:15   ` Ben Hutchings
@ 2010-11-02  2:24   ` Matt Carlson
  2010-11-03 22:29     ` Micha?? Miros??aw
  1 sibling, 1 reply; 22+ messages in thread
From: Matt Carlson @ 2010-11-02  2:24 UTC (permalink / raw)
  To: Micha?? Miros??aw
  Cc: linux-net-drivers, Debashis Dutt, e1000-devel, netdev,
	Greg Kroah-Hartman, Rasesh Mody, linux-driver, Steve Glendinning,
	Kristoffer Glembo

On Fri, Oct 29, 2010 at 09:28:26PM -0700, Micha?? Miros??aw wrote:
> diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
> index 30ccbb6..b07e2d1 100644
> --- a/drivers/net/tg3.c
> +++ b/drivers/net/tg3.c
> @@ -11306,7 +11306,6 @@ static const struct ethtool_ops tg3_ethtool_ops = {
>         .get_rx_csum            = tg3_get_rx_csum,
>         .set_rx_csum            = tg3_set_rx_csum,
>         .set_tx_csum            = tg3_set_tx_csum,
> -       .set_sg                 = ethtool_op_set_sg,
>         .set_tso                = tg3_set_tso,
>         .self_test              = tg3_self_test,
>         .get_strings            = tg3_get_strings,
> @@ -14681,6 +14680,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
>         tp->rx_pending = TG3_DEF_RX_RING_PENDING;
>         tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
> 
> +       dev->hw_features |= NETIF_F_SG;

Scatter-gather should not be enabled if TG3_FLAG_BROKEN_CHECKSUMS is set.  I
would do the following instead:

	if (!(tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS))
		dev->hw_features |= NETIF_F_SG;

TG3_FLAG_BROKEN_CHECKSUMS is set in tg3_get_invariants(), so this code
would need to be placed later than that function call.

>         dev->ethtool_ops = &tg3_ethtool_ops;
>         dev->watchdog_timeo = TG3_TX_TIMEOUT;
>         dev->irq = pdev->irq;


------------------------------------------------------------------------------
Nokia and AT&T present the 2010 Calling All Innovators-North America contest
Create new apps & games for the Nokia N8 for consumers in  U.S. and Canada
$10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing
Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store 
http://p.sf.net/sfu/nokia-dev2dev
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags
  2010-10-30  8:44 ` [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags Michał Mirosław
  2010-11-01 21:25   ` Ben Hutchings
@ 2010-11-02  2:49   ` Matt Carlson
  1 sibling, 0 replies; 22+ messages in thread
From: Matt Carlson @ 2010-11-02  2:49 UTC (permalink / raw)
  To: Micha?? Miros??aw
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Sat, Oct 30, 2010 at 01:44:17AM -0700, Micha?? Miros??aw wrote:
> diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
> index b07e2d1..c08172d 100644
> --- a/drivers/net/tg3.c
> +++ b/drivers/net/tg3.c
> @@ -6142,7 +6142,7 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
>         if (new_mtu > ETH_DATA_LEN) {
>                 if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
>                         tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
> -                       ethtool_op_set_tso(dev, 0);
> +                       dev->features &= ~NETIF_F_ALL_TSO;
>                 } else {
>                         tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE;
>                 }
> @@ -9977,27 +9977,28 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
>  {
>         struct tg3 *tp = netdev_priv(dev);
> 
> -       if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
> -               if (value)
> -                       return -EINVAL;
> +       if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && value)
> +               return -EINVAL;
> +
> +       if (!value)
>                 return 0;
> -       }
> +
> +       dev->features |= NETIF_F_TSO;
> +
>         if ((dev->features & NETIF_F_IPV6_CSUM) &&
>             ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) ||
>              (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3))) {
> -               if (value) {
> -                       dev->features |= NETIF_F_TSO6;
> -                       if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) ||
> -                           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
> -                           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
> -                            GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
> -                           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
> -                           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
> -                               dev->features |= NETIF_F_TSO_ECN;
> -               } else
> -                       dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
> +               dev->features |= NETIF_F_TSO6;
> +               if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) ||
> +                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
> +                   (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
> +                    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
> +                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
> +                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
> +                       dev->features |= NETIF_F_TSO_ECN;
>         }
> -       return ethtool_op_set_tso(dev, value);
> +
> +       return 1;

dev->hw_features looks to me like it should function as a set of flags
indicating what the hardware is currently capable of doing.  It would
clean the above code a lot if we could do:

	dev->features |= (dev->hw_features & NETIF_F_ALL_TSO);

In fact, the new member might serve as a replacement for the
TG3_FLG2_TSO_CAPABLE flag.  Let's not do that right now though,
because it requires some careful attention in other code paths which would
be a distraction.  I'll follow-up with a patch to do this.

>  }
> 
>  static int tg3_nway_reset(struct net_device *dev)
> @@ -11306,7 +11307,7 @@ static const struct ethtool_ops tg3_ethtool_ops = {
>         .get_rx_csum            = tg3_get_rx_csum,
>         .set_rx_csum            = tg3_set_rx_csum,
>         .set_tx_csum            = tg3_set_tx_csum,
> -       .set_tso                = tg3_set_tso,
> +       .hw_set_tso             = tg3_set_tso,
>         .self_test              = tg3_self_test,
>         .get_strings            = tg3_get_strings,
>         .phys_id                = tg3_phys_id,
> @@ -14681,6 +14682,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
>         tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
> 
>         dev->hw_features |= NETIF_F_SG;
> +       dev->hw_features |= NETIF_F_TSO|NETIF_F_TSO6|NETIF_F_TSO_ECN;

Not all devices are TSO capable either.  There is code later in this
function that determines which TSO flags to set.  I would probably reuse
that code.

>         dev->ethtool_ops = &tg3_ethtool_ops;
>         dev->watchdog_timeo = TG3_TX_TIMEOUT;
>         dev->irq = pdev->irq;


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag
  2010-11-02  2:24   ` Matt Carlson
@ 2010-11-03 22:29     ` Micha?? Miros??aw
  2010-11-03 22:42       ` Matt Carlson
  0 siblings, 1 reply; 22+ messages in thread
From: Micha?? Miros??aw @ 2010-11-03 22:29 UTC (permalink / raw)
  To: Matt Carlson
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Mon, Nov 01, 2010 at 07:24:38PM -0700, Matt Carlson wrote:
> On Fri, Oct 29, 2010 at 09:28:26PM -0700, Micha?? Miros??aw wrote:
> > diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
> > index 30ccbb6..b07e2d1 100644
> > --- a/drivers/net/tg3.c
> > +++ b/drivers/net/tg3.c
> > @@ -11306,7 +11306,6 @@ static const struct ethtool_ops tg3_ethtool_ops = {
> >         .get_rx_csum            = tg3_get_rx_csum,
> >         .set_rx_csum            = tg3_set_rx_csum,
> >         .set_tx_csum            = tg3_set_tx_csum,
> > -       .set_sg                 = ethtool_op_set_sg,
> >         .set_tso                = tg3_set_tso,
> >         .self_test              = tg3_self_test,
> >         .get_strings            = tg3_get_strings,
> > @@ -14681,6 +14680,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
> >         tp->rx_pending = TG3_DEF_RX_RING_PENDING;
> >         tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
> > 
> > +       dev->hw_features |= NETIF_F_SG;
> Scatter-gather should not be enabled if TG3_FLAG_BROKEN_CHECKSUMS is set.  I
> would do the following instead:
> 
> 	if (!(tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS))
> 		dev->hw_features |= NETIF_F_SG;
> 
> TG3_FLAG_BROKEN_CHECKSUMS is set in tg3_get_invariants(), so this code
> would need to be placed later than that function call.

This bug is there now, so I'll queue this as all other hints of existent
bugs that this patch series "uncovers".

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag
  2010-11-03 22:29     ` Micha?? Miros??aw
@ 2010-11-03 22:42       ` Matt Carlson
  2010-11-03 22:58         ` Michał Mirosław
  0 siblings, 1 reply; 22+ messages in thread
From: Matt Carlson @ 2010-11-03 22:42 UTC (permalink / raw)
  To: Micha?? Miros??aw
  Cc: Matthew Carlson, netdev, e1000-devel, Steve Glendinning,
	Greg Kroah-Hartman, Rasesh Mody, Debashis Dutt,
	Kristoffer Glembo, linux-driver, linux-net-drivers

On Wed, Nov 03, 2010 at 03:29:10PM -0700, Micha?? Miros??aw wrote:
> On Mon, Nov 01, 2010 at 07:24:38PM -0700, Matt Carlson wrote:
> > On Fri, Oct 29, 2010 at 09:28:26PM -0700, Micha?? Miros??aw wrote:
> > > diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
> > > index 30ccbb6..b07e2d1 100644
> > > --- a/drivers/net/tg3.c
> > > +++ b/drivers/net/tg3.c
> > > @@ -11306,7 +11306,6 @@ static const struct ethtool_ops tg3_ethtool_ops = {
> > >         .get_rx_csum            = tg3_get_rx_csum,
> > >         .set_rx_csum            = tg3_set_rx_csum,
> > >         .set_tx_csum            = tg3_set_tx_csum,
> > > -       .set_sg                 = ethtool_op_set_sg,
> > >         .set_tso                = tg3_set_tso,
> > >         .self_test              = tg3_self_test,
> > >         .get_strings            = tg3_get_strings,
> > > @@ -14681,6 +14680,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
> > >         tp->rx_pending = TG3_DEF_RX_RING_PENDING;
> > >         tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
> > > 
> > > +       dev->hw_features |= NETIF_F_SG;
> > Scatter-gather should not be enabled if TG3_FLAG_BROKEN_CHECKSUMS is set.  I
> > would do the following instead:
> > 
> > 	if (!(tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS))
> > 		dev->hw_features |= NETIF_F_SG;
> > 
> > TG3_FLAG_BROKEN_CHECKSUMS is set in tg3_get_invariants(), so this code
> > would need to be placed later than that function call.
> 
> This bug is there now, so I'll queue this as all other hints of existent
> bugs that this patch series "uncovers".

How so?  This patch would be introducing the bug.  From tg3_get_invariants:

	if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
		tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
	else {
		unsigned long features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO;

		tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
		if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
			features |= NETIF_F_IPV6_CSUM;
		tp->dev->features |= features;
		vlan_features_add(tp->dev, features);
	}


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag
  2010-11-03 22:42       ` Matt Carlson
@ 2010-11-03 22:58         ` Michał Mirosław
  0 siblings, 0 replies; 22+ messages in thread
From: Michał Mirosław @ 2010-11-03 22:58 UTC (permalink / raw)
  To: Matt Carlson
  Cc: netdev, e1000-devel, Steve Glendinning, Greg Kroah-Hartman,
	Rasesh Mody, Debashis Dutt, Kristoffer Glembo, linux-driver,
	linux-net-drivers

On Wed, Nov 03, 2010 at 03:42:47PM -0700, Matt Carlson wrote:
> On Wed, Nov 03, 2010 at 03:29:10PM -0700, Micha?? Miros??aw wrote:
> > On Mon, Nov 01, 2010 at 07:24:38PM -0700, Matt Carlson wrote:
> > > On Fri, Oct 29, 2010 at 09:28:26PM -0700, Micha?? Miros??aw wrote:
> > > > diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
> > > > index 30ccbb6..b07e2d1 100644
> > > > --- a/drivers/net/tg3.c
> > > > +++ b/drivers/net/tg3.c
> > > > @@ -11306,7 +11306,6 @@ static const struct ethtool_ops tg3_ethtool_ops = {
> > > >         .get_rx_csum            = tg3_get_rx_csum,
> > > >         .set_rx_csum            = tg3_set_rx_csum,
> > > >         .set_tx_csum            = tg3_set_tx_csum,
> > > > -       .set_sg                 = ethtool_op_set_sg,

This is exchanged ...

> > > >         .set_tso                = tg3_set_tso,
> > > >         .self_test              = tg3_self_test,
> > > >         .get_strings            = tg3_get_strings,
> > > > @@ -14681,6 +14680,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
> > > >         tp->rx_pending = TG3_DEF_RX_RING_PENDING;
> > > >         tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
> > > > 
> > > > +       dev->hw_features |= NETIF_F_SG;

... for this. (This introduces no functional changes, whatsoever.)

> > > Scatter-gather should not be enabled if TG3_FLAG_BROKEN_CHECKSUMS is set.  I
> > > would do the following instead:
> > > 
> > > 	if (!(tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS))
> > > 		dev->hw_features |= NETIF_F_SG;
> > > 
> > > TG3_FLAG_BROKEN_CHECKSUMS is set in tg3_get_invariants(), so this code
> > > would need to be placed later than that function call.
> > 
> > This bug is there now, so I'll queue this as all other hints of existent
> > bugs that this patch series "uncovers".
> 
> How so?  This patch would be introducing the bug.  From tg3_get_invariants:
> 
> 	if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
> 		tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
> 	else {
> 		unsigned long features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO;
> 
> 		tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
> 		if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
> 			features |= NETIF_F_IPV6_CSUM;
> 		tp->dev->features |= features;
> 		vlan_features_add(tp->dev, features);
> 	}

Actually this is hidden anyway, because currently scatter-gather depends
on checksumming offload. So the SG won't be enabled based on check left
in ethtool_set_sg().

Note, that hw_features flags enable toggling of the offloads but don't
enable them unless requested by a user later.

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2010-11-03 22:58 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-31  3:40 [PATCH 0/4] Ethtool: cleanup strategy Michał Mirosław
2010-10-30  4:27 ` [PATCH 1/4] Ethtool: Introduce hw_features field in struct netdevice Michał Mirosław
2010-10-30  4:28 ` [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag Michał Mirosław
2010-11-01 21:15   ` Ben Hutchings
2010-11-02  0:59     ` Michał Mirosław
2010-11-02  2:24   ` Matt Carlson
2010-11-03 22:29     ` Micha?? Miros??aw
2010-11-03 22:42       ` Matt Carlson
2010-11-03 22:58         ` Michał Mirosław
2010-10-30  8:44 ` [PATCH 3/4] Ethtool: convert get_tso/set_tso calls to hw_features flags Michał Mirosław
2010-11-01 21:25   ` Ben Hutchings
2010-11-02  1:14     ` Michał Mirosław
2010-11-02  2:49   ` Matt Carlson
2010-10-31  0:09 ` [PATCH 4/4] Ethtool: convert get_tx_csum/set_tx_csum " Michał Mirosław
2010-11-01 21:38   ` Ben Hutchings
2010-11-02  1:23     ` Michał Mirosław
2010-10-31  4:18 ` [PATCH 0/4] Ethtool: cleanup strategy David Miller
2010-10-31  4:30   ` Michał Mirosław
2010-11-01 21:05 ` Ben Hutchings
2010-11-02  1:02   ` Michał Mirosław
2010-11-02  1:14     ` Ben Hutchings
2010-11-02  1:30       ` Michał Mirosław

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.