Netdev List
 help / color / mirror / Atom feed
* [PATCH 1/4] Ethtool: Introduce hw_features field in struct netdevice
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
In-Reply-To: <cover.1288496404.git.mirq-linux@rere.qmqm.pl>


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

* [PATCH 4/4] Ethtool: convert get_tx_csum/set_tx_csum calls to hw_features flags
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
In-Reply-To: <cover.1288496404.git.mirq-linux@rere.qmqm.pl>


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

* [PATCH 2/4] Ethtool: convert get_sg/set_sg calls to hw_features flag
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
In-Reply-To: <cover.1288496404.git.mirq-linux@rere.qmqm.pl>


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

* [PATCH 0/4] Ethtool: cleanup strategy
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

* [ANNOUNCE] Host Fabric Interface (HFI) device driver available on sourceforge
From: Jim Dykman @ 2010-10-31  3:10 UTC (permalink / raw)
  To: netdev

The HFI network interface is the internal cluster fabric of IBM's PERCS 
supercomputer. The device driver patch for 2.6.36, hfi-utils, and an 
introduction to the hardware are available on the sourceforge page 
(http://sourceforge.net/projects/hfidevicedriver). The hardware design 
is under US export control, so we cannot release hardware specs.

The HFI device driver allows direct user-space access to network 
resources; a reference library will be uploaded to 
http://sourceforge.net/projects/halreferencelib in the next few days.

The driver has been running in the lab for several months. The 
user-space access is essentially complete. We are still working on IPv6, 
and we are now starting work on an ofed-over-hfi driver, but we'd like 
to start the review process without them.

Jim Dykman


^ permalink raw reply

* [GIT] Networking
From: David Miller @ 2010-10-31  1:32 UTC (permalink / raw)
  To: torvalds; +Cc: akpm, netdev, linux-kernel


Last pull request before 2.6.37-rc1, I really wanted to get your
sendto/recvfrom patch in here as well as the RDS fixes.

I did a bunch of tests with the various I/O calls using different
lengths, like 10, (2^31 - 1), 2^31, 2^32, and larger on 64-bit and it
all seems to be doing the right thing at least with TCP and UDP.

Also:

1) Fix ipv6 UDP statistic regression, from Eric Dumazet.

2) Fix GRE fallback tunnel init, also from Eric Dumazet.

3) Endianness fixes from vmxnet driver, from Harvey Harrison.

4) New ID for pcnet_cs driver.

5) Stack info leak to userland fix in mISDN, from Kulikov Vasiliy.

6) netxen_nic probe crash due to too early tx queue manipulation,
   fix from Denis Kirjanov.

7) RDS fixes from you and Andy Grover.

8) Fix sparse and section mismatch problems in new pch_can driver,
   from Marc Kleine-Budde.

Please pull, thanks a lot!

The following changes since commit b7bdcc47114595b4b359fe0f7d941bb901e9261d:

  Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-kconfig (2010-10-29 14:43:30 -0700)

are available in the git repository at:

  master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6.git master

Andy Grover (4):
      RDS: Return -EINVAL if rds_rdma_pages returns an error
      RDS: Clean up error handling in rds_cmsg_rdma_args
      RDS: Copy rds_iovecs into kernel memory instead of rereading from userspace
      RDS: Let rds_message_alloc_sgs() return NULL

Cyril Chemparathy (1):
      phy/marvell: rename 88ec048 to 88e1318s and fix mscr1 addr

Denis Kirjanov (1):
      netxen_nic: Fix the tx queue manipulation bug in netxen_nic_probe

Eric Dumazet (2):
      ipv6/udp: report SndbufErrors and RcvbufErrors
      ip_gre: fix fallback tunnel setup

Hans J. Koch (1):
      netdev: can: Change mail address of Hans J. Koch

Harvey Harrison (2):
      vmxnet3: remove unnecessary byteswapping in BAR writing macros
      vmxnet: trivial annotation of protocol constant

Ken Kawasaki (1):
      pcnet_cs: add new_id

Kulikov Vasiliy (1):
      isdn: mISDN: socket: fix information leak to userland

Linus Torvalds (2):
      net: fix rds_iovec page count overflow
      net: Truncate recvfrom and sendto length to INT_MAX.

Marc Kleine-Budde (2):
      can: pch_can: fix sparse warning
      can: pch_can: fix section mismatch warning by using a whitelisted name

 drivers/isdn/mISDN/socket.c          |    2 +
 drivers/net/can/at91_can.c           |    2 +-
 drivers/net/can/pch_can.c            |   10 ++--
 drivers/net/netxen/netxen_nic_main.c |    1 -
 drivers/net/pcmcia/pcnet_cs.c        |    1 +
 drivers/net/phy/marvell.c            |   18 +++---
 drivers/net/vmxnet3/vmxnet3_drv.c    |    2 +-
 drivers/net/vmxnet3/vmxnet3_int.h    |    8 +-
 include/linux/marvell_phy.h          |    2 +-
 net/ipv4/ip_gre.c                    |    6 +-
 net/ipv6/proc.c                      |    4 +
 net/rds/message.c                    |    5 ++
 net/rds/rdma.c                       |  126 ++++++++++++++++++++++-----------
 net/rds/send.c                       |    4 +
 net/socket.c                         |    4 +
 15 files changed, 128 insertions(+), 67 deletions(-)

^ permalink raw reply

* [net-next-2.6 PATCH 3/3] net: consolidate 8021q tagging
From: John Fastabend @ 2010-10-31  0:22 UTC (permalink / raw)
  To: davem; +Cc: netdev, jesse
In-Reply-To: <20101031002232.8691.41201.stgit@jf-dev1-dcblab>

Now that VLAN packets are tagged in dev_hard_start_xmit()
at the bottom of the stack we no longer need to tag them
in the 8021Q module (Except in the !VLAN_FLAG_REORDER_HDR
case).

This allows the accel path and non accel paths to be consolidated.
Here the vlan_tci in the skb is always set and we allow the
stack to add the actual tag in dev_hard_start_xmit().

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---

 net/8021q/vlan.h     |    4 --
 net/8021q/vlan_dev.c |  105 +++-----------------------------------------------
 net/8021q/vlanproc.c |    4 --
 3 files changed, 7 insertions(+), 106 deletions(-)

diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index db01b31..4625ba6 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -45,8 +45,6 @@ struct vlan_rx_stats {
  *	@real_dev: underlying netdevice
  *	@real_dev_addr: address of underlying netdevice
  *	@dent: proc dir entry
- *	@cnt_inc_headroom_on_tx: statistic - number of skb expansions on TX
- *	@cnt_encap_on_xmit: statistic - number of skb encapsulations on TX
  *	@vlan_rx_stats: ptr to percpu rx stats
  */
 struct vlan_dev_info {
@@ -62,8 +60,6 @@ struct vlan_dev_info {
 	unsigned char				real_dev_addr[ETH_ALEN];
 
 	struct proc_dir_entry			*dent;
-	unsigned long				cnt_inc_headroom_on_tx;
-	unsigned long				cnt_encap_on_xmit;
 	struct vlan_rx_stats __percpu		*vlan_rx_stats;
 };
 
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index afb03c5..f3c9552 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -323,24 +323,12 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
 	 */
 	if (veth->h_vlan_proto != htons(ETH_P_8021Q) ||
 	    vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) {
-		unsigned int orig_headroom = skb_headroom(skb);
 		u16 vlan_tci;
-
-		vlan_dev_info(dev)->cnt_encap_on_xmit++;
-
 		vlan_tci = vlan_dev_info(dev)->vlan_id;
 		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
-		skb = __vlan_put_tag(skb, vlan_tci);
-		if (!skb) {
-			txq->tx_dropped++;
-			return NETDEV_TX_OK;
-		}
-
-		if (orig_headroom < VLAN_HLEN)
-			vlan_dev_info(dev)->cnt_inc_headroom_on_tx++;
+		skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
 	}
 
-
 	skb_set_dev(skb, vlan_dev_info(dev)->real_dev);
 	len = skb->len;
 	ret = dev_queue_xmit(skb);
@@ -354,32 +342,6 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
 	return ret;
 }
 
-static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb,
-						    struct net_device *dev)
-{
-	int i = skb_get_queue_mapping(skb);
-	struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
-	u16 vlan_tci;
-	unsigned int len;
-	int ret;
-
-	vlan_tci = vlan_dev_info(dev)->vlan_id;
-	vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
-	skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
-
-	skb->dev = vlan_dev_info(dev)->real_dev;
-	len = skb->len;
-	ret = dev_queue_xmit(skb);
-
-	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
-		txq->tx_packets++;
-		txq->tx_bytes += len;
-	} else
-		txq->tx_dropped++;
-
-	return ret;
-}
-
 static u16 vlan_dev_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
 	struct net_device *rdev = vlan_dev_info(dev)->real_dev;
@@ -716,8 +678,7 @@ static const struct header_ops vlan_header_ops = {
 	.parse	 = eth_header_parse,
 };
 
-static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops,
-		    vlan_netdev_ops_sq, vlan_netdev_accel_ops_sq;
+static const struct net_device_ops vlan_netdev_ops, vlan_netdev_ops_sq;
 
 static int vlan_dev_init(struct net_device *dev)
 {
@@ -752,19 +713,16 @@ static int vlan_dev_init(struct net_device *dev)
 	if (real_dev->features & NETIF_F_HW_VLAN_TX) {
 		dev->header_ops      = real_dev->header_ops;
 		dev->hard_header_len = real_dev->hard_header_len;
-		if (real_dev->netdev_ops->ndo_select_queue)
-			dev->netdev_ops = &vlan_netdev_accel_ops_sq;
-		else
-			dev->netdev_ops = &vlan_netdev_accel_ops;
 	} else {
 		dev->header_ops      = &vlan_header_ops;
 		dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
-		if (real_dev->netdev_ops->ndo_select_queue)
-			dev->netdev_ops = &vlan_netdev_ops_sq;
-		else
-			dev->netdev_ops = &vlan_netdev_ops;
 	}
 
+	if (real_dev->netdev_ops->ndo_select_queue)
+		dev->netdev_ops = &vlan_netdev_ops_sq;
+	else
+		dev->netdev_ops = &vlan_netdev_ops;
+
 	if (is_vlan_dev(real_dev))
 		subclass = 1;
 
@@ -905,30 +863,6 @@ static const struct net_device_ops vlan_netdev_ops = {
 #endif
 };
 
-static const struct net_device_ops vlan_netdev_accel_ops = {
-	.ndo_change_mtu		= vlan_dev_change_mtu,
-	.ndo_init		= vlan_dev_init,
-	.ndo_uninit		= vlan_dev_uninit,
-	.ndo_open		= vlan_dev_open,
-	.ndo_stop		= vlan_dev_stop,
-	.ndo_start_xmit =  vlan_dev_hwaccel_hard_start_xmit,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address	= vlan_dev_set_mac_address,
-	.ndo_set_rx_mode	= vlan_dev_set_rx_mode,
-	.ndo_set_multicast_list	= vlan_dev_set_rx_mode,
-	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
-	.ndo_do_ioctl		= vlan_dev_ioctl,
-	.ndo_neigh_setup	= vlan_dev_neigh_setup,
-	.ndo_get_stats64	= vlan_dev_get_stats64,
-#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
-	.ndo_fcoe_ddp_setup	= vlan_dev_fcoe_ddp_setup,
-	.ndo_fcoe_ddp_done	= vlan_dev_fcoe_ddp_done,
-	.ndo_fcoe_enable	= vlan_dev_fcoe_enable,
-	.ndo_fcoe_disable	= vlan_dev_fcoe_disable,
-	.ndo_fcoe_get_wwn	= vlan_dev_fcoe_get_wwn,
-#endif
-};
-
 static const struct net_device_ops vlan_netdev_ops_sq = {
 	.ndo_select_queue	= vlan_dev_select_queue,
 	.ndo_change_mtu		= vlan_dev_change_mtu,
@@ -954,31 +888,6 @@ static const struct net_device_ops vlan_netdev_ops_sq = {
 #endif
 };
 
-static const struct net_device_ops vlan_netdev_accel_ops_sq = {
-	.ndo_select_queue	= vlan_dev_select_queue,
-	.ndo_change_mtu		= vlan_dev_change_mtu,
-	.ndo_init		= vlan_dev_init,
-	.ndo_uninit		= vlan_dev_uninit,
-	.ndo_open		= vlan_dev_open,
-	.ndo_stop		= vlan_dev_stop,
-	.ndo_start_xmit =  vlan_dev_hwaccel_hard_start_xmit,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address	= vlan_dev_set_mac_address,
-	.ndo_set_rx_mode	= vlan_dev_set_rx_mode,
-	.ndo_set_multicast_list	= vlan_dev_set_rx_mode,
-	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
-	.ndo_do_ioctl		= vlan_dev_ioctl,
-	.ndo_neigh_setup	= vlan_dev_neigh_setup,
-	.ndo_get_stats64	= vlan_dev_get_stats64,
-#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
-	.ndo_fcoe_ddp_setup	= vlan_dev_fcoe_ddp_setup,
-	.ndo_fcoe_ddp_done	= vlan_dev_fcoe_ddp_done,
-	.ndo_fcoe_enable	= vlan_dev_fcoe_enable,
-	.ndo_fcoe_disable	= vlan_dev_fcoe_disable,
-	.ndo_fcoe_get_wwn	= vlan_dev_fcoe_get_wwn,
-#endif
-};
-
 void vlan_setup(struct net_device *dev)
 {
 	ether_setup(dev);
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index 80e280f..8a64db1 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -299,10 +299,6 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
 	seq_puts(seq, "\n");
 	seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
 	seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
-	seq_printf(seq, fmt, "total headroom inc",
-		   dev_info->cnt_inc_headroom_on_tx);
-	seq_printf(seq, fmt, "total encap on xmit",
-		   dev_info->cnt_encap_on_xmit);
 	seq_printf(seq, "Device: %s", dev_info->real_dev->name);
 	/* now show all PRIORITY mappings relating to this VLAN */
 	seq_printf(seq, "\nINGRESS priority mappings: "


^ permalink raw reply related

* [net-next-2.6 PATCH 2/3] net: remove check for headroom in vlan_dev_create
From: John Fastabend @ 2010-10-31  0:22 UTC (permalink / raw)
  To: davem; +Cc: netdev, jesse
In-Reply-To: <20101031002232.8691.41201.stgit@jf-dev1-dcblab>

It is possible for the headroom to be smaller then the
hard_header_len for a short period of time after toggling
the vlan offload setting.

This is not a hard error and skb_cow_head is called in
__vlan_put_tag() to resolve this.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---

 net/8021q/vlan_dev.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 14e3d1f..afb03c5 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -274,9 +274,6 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
 	u16 vlan_tci = 0;
 	int rc;
 
-	if (WARN_ON(skb_headroom(skb) < dev->hard_header_len))
-		return -ENOSPC;
-
 	if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) {
 		vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);
 


^ permalink raw reply related

* [net-next-2.6 PATCH 1/3] 8021q: set hard_header_len when VLAN offload features are toggled
From: John Fastabend @ 2010-10-31  0:22 UTC (permalink / raw)
  To: davem; +Cc: netdev, jesse

Toggling the vlan tx|rx hw offloads needs to set the hard_header_len
as well otherwise we end up using LL_RESERVED_SPACE incorrectly.
This results in pskb_expand_head() being used unnecessarily.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---

 net/8021q/vlan.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 05b867e..cb78b99 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -334,6 +334,12 @@ static void vlan_transfer_features(struct net_device *dev,
 	vlandev->features &= ~dev->vlan_features;
 	vlandev->features |= dev->features & dev->vlan_features;
 	vlandev->gso_max_size = dev->gso_max_size;
+
+	if (dev->features & NETIF_F_HW_VLAN_TX)
+		vlandev->hard_header_len = dev->hard_header_len;
+	else
+		vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN;
+
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
 	vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;
 #endif


^ permalink raw reply related

* Re: [PATCH 5/6] netdev: can: Change mail address of Hans J. Koch
From: David Miller @ 2010-10-30 23:50 UTC (permalink / raw)
  To: hjk; +Cc: linux-kernel, netdev
In-Reply-To: <20101029223357.GF4331@local>

From: "Hans J. Koch" <hjk@hansjkoch.de>
Date: Sat, 30 Oct 2010 00:33:57 +0200

> My old mail address doesn't exist anymore. This changes all occurrences
> to my new address.
> 
> Signed-off-by: Hans J. Koch <hjk@hansjkoch.de>

Applied.

^ permalink raw reply

* Re: [PATCH] isdn: mISDN: socket: fix information leak to userland
From: David Miller @ 2010-10-30 23:49 UTC (permalink / raw)
  To: segooon; +Cc: kernel-janitors, isdn, acme, tj, eparis, netdev, linux-kernel
In-Reply-To: <1288429473-21864-1-git-send-email-segooon@gmail.com>

From: Vasiliy Kulikov <segooon@gmail.com>
Date: Sat, 30 Oct 2010 13:04:33 +0400

> Structure mISDN_devinfo is copied to userland with the field "name"
> that has the last elements unitialized.  It leads to leaking of
> contents of kernel stack memory.
> 
> Signed-off-by: Vasiliy Kulikov <segooon@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH kernel 2.6.36-git10] pcnet_cs: add new_id
From: David Miller @ 2010-10-30 23:49 UTC (permalink / raw)
  To: ken_kawasaki; +Cc: netdev
In-Reply-To: <20101030071751.63611ede.ken_kawasaki@spring.nifty.jp>

From: Ken Kawasaki <ken_kawasaki@spring.nifty.jp>
Date: Sat, 30 Oct 2010 07:17:51 +0900

> 
> pcnet_cs:
>     add new_id: "corega Ether CF-TD" 10Base-T PCMCIA card.
> 
> 
> Signed-off-by: Ken Kawasaki <ken_kawasaki@spring.nifty.jp>

Applied.

^ permalink raw reply

* Re: [GIT] Networking
From: David Miller @ 2010-10-30 23:47 UTC (permalink / raw)
  To: torvalds; +Cc: akpm, netdev, linux-kernel
In-Reply-To: <AANLkTinR6XH30dHwPS23=sGYOJU8rO4+kwz+Uv_XRB-b@mail.gmail.com>

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Fri, 29 Oct 2010 14:41:03 -0700

> On Fri, Oct 29, 2010 at 12:59 PM, David Miller <davem@davemloft.net> wrote:
>>
>> This has the verify_iovec() INT_MAX limiter change as well as:
> 
> I think you'd want this as well, to make sure that sendto/recvfrom
> don't generate invalid iovecs.
> 
> Feel free to add my sign-off (or just commit it as yourself) after
> giving it some testing.

Done, thanks.

> NOTE! On thing that struck me is that the VFS layer does the
> "access_ok()" on the pre-truncated size and pointer pair, and I think
> that is the correct thing to do. However, the socket layer (and this
> patch) just truncates the size, so even if the copy is then done
> correctly with the proper user access checking, it will not check that
> the whole original buffer was valid - only that the buffer it fills in
> is valid.
> 
> Now, this is not a security issue (since we're just not checking stuff
> that isn't getting filled in), but I think it's a QoI issue - it
> allows users to successfully pass in bogus buffers with huge sizes,
> and then if the thing only reads a few bytes it will all be ok.
> 
> That's not a new thing: the old code may not have truncated the sizes,
> but if you pass in a 2GB buffer size, 99.999% of all socket read calls
> obviously won't ever fill that 2GB, but will happily return with
> whatever is there in the socket now (especially with nonblocking IO
> etc). But I do wonder if we shouldn't do the access_ok() on the whole
> buffer, as a way to keep user code honest.

I honestly don't think it matters.

I suppose we could put the access_ok() check right before these
single-buffer truncations, and then also in the per-iovec check of
{compat_}verify_iovec().

But what would all of that really give us?

Ingrained in datagram socket handling is the idea that the whole
buffer will be processed, and for stream sockets partial buffer
transfers are OK.

And I think this aligns with how we implement and check things
right now.

^ permalink raw reply

* Re: [PATCH 0/5] RDS rds_iovec fixes
From: David Miller @ 2010-10-30 23:34 UTC (permalink / raw)
  To: andy.grover; +Cc: netdev, rds-devel
In-Reply-To: <1288316459-4679-1-git-send-email-andy.grover@oracle.com>

From: Andy Grover <andy.grover@oracle.com>
Date: Thu, 28 Oct 2010 18:40:54 -0700

> This patchset includes Linus' rds_iovec overflow fix, as well as making
> a copy of the rds_iovec array to prevent userspace from changing them after
> we've checked them.
> 
> Please especially review patch 5. We go from 3 to 2 iovec copies, but it's not
> trivial to go to one, due to some code that wants to preallocate space for SGs.
> Until that code can be changed, patch 5 attempts to safely handle the scenario.

I looked carefully over these and they look ok.

Applied, thanks Andy.

^ permalink raw reply

* Re: [PATCH 1/2] can: pch_can: fix sparse warning
From: David Miller @ 2010-10-30 23:28 UTC (permalink / raw)
  To: mkl-bIcnvbaLZ9MEGnE8C9+IrQ
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1288168706-870-2-git-send-email-mkl-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

From: Marc Kleine-Budde <mkl-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Date: Wed, 27 Oct 2010 10:38:25 +0200

> This patch fixes the following sparse warning:
> 
> drivers/net/can/pch_can.c:231:26: warning: incorrect type in argument 1 (different address spaces)
> drivers/net/can/pch_can.c:231:26:    expected unsigned int [usertype] *addr
> drivers/net/can/pch_can.c:231:26:    got unsigned int [noderef] <asn:2>*<noident>
> 
> Let pch_can_bit_{set,clear} first parameter be a void __iomem pointer.
> 
> Signed-off-by: Marc Kleine-Budde <mkl-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

Applied.

^ permalink raw reply

* Re: [PATCH 2/2] can: pch_can: fix section mismatch warning by using a whitelisted name
From: David Miller @ 2010-10-30 23:28 UTC (permalink / raw)
  To: mkl; +Cc: socketcan-core, netdev, tomoya-linux
In-Reply-To: <1288168706-870-3-git-send-email-mkl@pengutronix.de>

From: Marc Kleine-Budde <mkl@pengutronix.de>
Date: Wed, 27 Oct 2010 10:38:26 +0200

> This patch fixes the following section mismatch warning:
> 
> WARNING: drivers/net/can/pch_can.o(.data+0x18):
> Section mismatch in reference from the variable pch_can_pcidev
> to the variable .devinit.rodata:pch_pci_tbl
> The variable pch_can_pcidev references
> the variable __devinitconst pch_pci_tbl
> 
> This is actually a false positive which is fixed by giving the offending
> variable a whitelisted name, it's renamed to "pch_can_pci_driver".
> This makes sense because the variable is of the type "struct pci_driver".
> 
> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
> Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

Applied.

^ permalink raw reply

* Re: NULL pointer dereference at netxen_nic_probe+0x813/0x9a0
From: David Miller @ 2010-10-30 23:24 UTC (permalink / raw)
  To: dkirjanov; +Cc: bjorn.helgaas, amit.salecha, netdev, linux-kernel
In-Reply-To: <4CCC7868.60104@kernel.org>

From: Denis Kirjanov <dkirjanov@kernel.org>
Date: Sat, 30 Oct 2010 23:56:24 +0400

> [PATCH] netxen_nic: Fix the tx queue manipulation bug in netxen_nic_probe
> 
> We should not stop the egress queue during probe because it is wrong.
> 
> Signed-off-by: Denis Kirjanov <dkirjanov@kernel.org>

Applied.

^ permalink raw reply

* Re: [PATCH net-next-2.6 1/2] be2net: Adding an option to use INTx instead of MSI-X
From: Matthew Wilcox @ 2010-10-30 23:21 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: David Miller, bhutchings, somnath.kotur, netdev, linux-pci
In-Reply-To: <1288075928.6578.185.camel@concordia>

On Tue, Oct 26, 2010 at 05:52:08PM +1100, Michael Ellerman wrote:
> That horse has really really bolted, it's gawn.
> 
> I count 26 drivers with "disable MSI/X" parameters. Some even have more
> than one.

That's 26 patches someone needs to write, then.  You can put my Acked-by
on all of them.

> I agree it's a mess for users, but it's probably preferable to a
> non-working driver.

What more drivers need is an automatic detection of a non-working
interrupt situation, great big warning messages, and fallback to an
alternate interrupt mechanism.  Doing it for one driver, then generalising
as much of it into the core as possible would be nice.

-- 
Matthew Wilcox				Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."

^ permalink raw reply

* Re: [PATCH] ip_gre: fix fallback tunnel setup
From: David Miller @ 2010-10-30 23:21 UTC (permalink / raw)
  To: xemul; +Cc: eric.dumazet, netdev
In-Reply-To: <4CC9CF06.1090806@parallels.com>

From: Pavel Emelyanov <xemul@parallels.com>
Date: Thu, 28 Oct 2010 23:29:10 +0400

> On 10/28/2010 11:11 PM, Eric Dumazet wrote:
>> Le jeudi 28 octobre 2010 à 20:47 +0200, Eric Dumazet a écrit :
>>> Le jeudi 28 octobre 2010 à 11:41 -0700, David Miller a écrit :
>>>> I am still able to revert this I think without screwing up
>>>> publicly visible history, so I will double check and do the
>>>> revert if I can.
>>>
>>> Cool, I'll provide a patch in a couple of minutes, when tested.
>>>
>> 
>> I believe the right fix is this one, Pavel what do you think ?
> 
> Indeed. I missed the fact, that the gre driver uses ndo_init for
> all devices including the fb one :(
> 
> Acked-by: Pavel Emelyanov <xemul@openvz.org>

Applied.

^ permalink raw reply

* Re: [PATCH 2/2] vmxnet: trivial annotation of protocol constant
From: David Miller @ 2010-10-30 23:19 UTC (permalink / raw)
  To: harvey.harrison; +Cc: sbhatewara, netdev
In-Reply-To: <1288235555-24675-2-git-send-email-harvey.harrison@gmail.com>

From: Harvey Harrison <harvey.harrison@gmail.com>
Date: Wed, 27 Oct 2010 20:12:35 -0700

> Noticed by sparse:
> drivers/net/vmxnet3/vmxnet3_drv.c:876:38: warning: cast from restricted __be16
> drivers/net/vmxnet3/vmxnet3_drv.c:876:38: warning: cast from restricted __be16
> drivers/net/vmxnet3/vmxnet3_drv.c:876:24: warning: restricted __be16 degrades to integer
> 
> Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH 1/2] vmxnet3: remove unnecessary byteswapping in BAR writing macros
From: David Miller @ 2010-10-30 23:19 UTC (permalink / raw)
  To: harvey.harrison; +Cc: sbhatewara, netdev
In-Reply-To: <1288235555-24675-1-git-send-email-harvey.harrison@gmail.com>

From: Harvey Harrison <harvey.harrison@gmail.com>
Date: Wed, 27 Oct 2010 20:12:34 -0700

> readl/writel swap to little-endian internally.
> 
> Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH] ipv6/udp: report SndbufErrors and RcvbufErrors
From: David Miller @ 2010-10-30 23:17 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev, stable
In-Reply-To: <1288172116.2709.81.camel@edumazet-laptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Wed, 27 Oct 2010 11:35:16 +0200

> commit a18135eb9389 (Add UDP_MIB_{SND,RCV}BUFERRORS handling.)
> forgot to make the necessary changes in net/ipv6/proc.c to report
> additional counters in /proc/net/snmp6
> 
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH] af_unix: unix_write_space() use keyed wakeups
From: Alban Crequy @ 2010-10-30 21:36 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Davide Libenzi, David S. Miller, Stephen Hemminger,
	Cyrill Gorcunov, Alexey Dobriyan, netdev, linux-kernel,
	Pauli Nieminen, Rainer Weikusat
In-Reply-To: <1288421084.2680.717.camel@edumazet-laptop>

Le Sat, 30 Oct 2010 08:44:44 +0200,
Eric Dumazet <eric.dumazet@gmail.com> a écrit :

> We still loop on 800 items, on each wake_up_interruptible_sync_poll()
> call, so maybe we want to optimize this later, adding a global key,
> ORing all items keys. I dont think its worth the added complexity,
> given the biased usage of your program (800 'listeners' to one
> event). Is it a real life scenario ?

Pauli Nieminen told me about his performance problem in select() so I
wrote the test program but I don't know what exactly is the real life
scenario.

> [PATCH] af_unix: use keyed wakeups
> [PATCH] af_unix: optimize unix_dgram_poll()

Your 2 patches are good for me. In my opinion the improved performances
are good enough with your 2 patches, so no need to add more complexity
unless we discover new problems.

I am preparing patches to implement multicast features on Unix
datagram+seqpacket sockets and my patches could potentially make things
worse in unix_dgram_poll() because it would need to check the receiving
queues of all multicast members. So I want unix_dgram_poll() to be fast
in the first place before proposing other changes for multicast.

^ permalink raw reply

* [PATCH 38/39] net/rfkill/input.c: Update WARN uses
From: Joe Perches @ 2010-10-30 21:08 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: Johannes Berg, John W. Linville, David S. Miller, linux-wireless,
	netdev, linux-kernel
In-Reply-To: <cover.1288471897.git.joe@perches.com>

Coalesce long formats.
Align arguments.

Signed-off-by: Joe Perches <joe@perches.com>
---
 net/rfkill/input.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/net/rfkill/input.c b/net/rfkill/input.c
index 1bca6d4..4343f59 100644
--- a/net/rfkill/input.c
+++ b/net/rfkill/input.c
@@ -75,9 +75,8 @@ static void __rfkill_handle_global_op(enum rfkill_sched_op op)
 	default:
 		/* memory corruption or bug, fail safely */
 		rfkill_epo();
-		WARN(1, "Unknown requested operation %d! "
-			"rfkill Emergency Power Off activated\n",
-			op);
+		WARN(1, "Unknown requested operation %d! rfkill Emergency Power Off activated\n",
+		     op);
 	}
 }
 
-- 
1.7.3.1.g432b3.dirty


^ permalink raw reply related

* [PATCH 36/39] net/ipv4/tcp.c: Update WARN uses
From: Joe Perches @ 2010-10-30 21:08 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: David S. Miller, Alexey Kuznetsov, Pekka Savola (ipv6),
	James Morris, Hideaki YOSHIFUJI, Patrick McHardy, netdev,
	linux-kernel
In-Reply-To: <cover.1288471897.git.joe@perches.com>

Coalesce long formats.
Align arguments.
Remove KERN_<level>.

Signed-off-by: Joe Perches <joe@perches.com>
---
 net/ipv4/tcp.c |   16 +++++++---------
 1 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 1664a05..5f738c5 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1193,7 +1193,7 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied)
 	struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
 
 	WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq),
-	     KERN_INFO "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n",
+	     "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n",
 	     tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt);
 #endif
 
@@ -1477,10 +1477,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 			 * shouldn't happen.
 			 */
 			if (WARN(before(*seq, TCP_SKB_CB(skb)->seq),
-			     KERN_INFO "recvmsg bug: copied %X "
-				       "seq %X rcvnxt %X fl %X\n", *seq,
-				       TCP_SKB_CB(skb)->seq, tp->rcv_nxt,
-				       flags))
+				 "recvmsg bug: copied %X seq %X rcvnxt %X fl %X\n",
+				 *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt,
+				 flags))
 				break;
 
 			offset = *seq - TCP_SKB_CB(skb)->seq;
@@ -1490,10 +1489,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 				goto found_ok_skb;
 			if (tcp_hdr(skb)->fin)
 				goto found_fin_ok;
-			WARN(!(flags & MSG_PEEK), KERN_INFO "recvmsg bug 2: "
-					"copied %X seq %X rcvnxt %X fl %X\n",
-					*seq, TCP_SKB_CB(skb)->seq,
-					tp->rcv_nxt, flags);
+			WARN(!(flags & MSG_PEEK),
+			     "recvmsg bug 2: copied %X seq %X rcvnxt %X fl %X\n",
+			     *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt, flags);
 		}
 
 		/* Well, if we have backlog, try to process it now yet. */
-- 
1.7.3.1.g432b3.dirty


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox