From: Herbert Xu <herbert@gondor.apana.org.au> Date: Wed, 27 May 2009 15:31:20 +1000 Subject: [net] ethtool: add GGRO and SGRO ops Message-id: E1M9BjU-0002CM-JX@gondolin.me.apana.org.au O-Subject: [PATCH 15/17] ethtool: Add GGRO and SGRO ops Bugzilla: 499347 RH-Acked-by: David Miller <davem@redhat.com> RH-Acked-by: Neil Horman <nhorman@redhat.com> RH-Acked-by: Thomas Graf <tgraf@redhat.com> RHEL5 bugzilla #499347 ethtool: Add GGRO and SGRO ops This patch adds the ethtool ops to enable and disable GRO. It also makes GRO depend on RX checksum offload much the same as how TSO depends on SG support. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net> diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index f2d248f..0f64eec 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -413,6 +413,8 @@ struct ethtool_ops { #define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ #define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */ #define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */ +#define ETHTOOL_GGRO 0x0000002b /* Get GRO enable (ethtool_value) */ +#define ETHTOOL_SGRO 0x0000002c /* Set GRO enable (ethtool_value) */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 9db6992..7824d0d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -470,6 +470,9 @@ 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) + dev->features &= ~NETIF_F_GRO; + dev->ethtool_ops->set_rx_csum(dev, edata.data); return 0; } @@ -637,6 +640,34 @@ static int ethtool_set_gso(struct net_device *dev, char __user *useraddr) return 0; } +static int ethtool_get_gro(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GGRO }; + + edata.data = dev->features & NETIF_F_GRO; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_gro(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + if (edata.data) { + if (!dev->ethtool_ops->get_rx_csum || + !dev->ethtool_ops->get_rx_csum(dev)) + return -EINVAL; + dev->features |= NETIF_F_GRO; + } else + dev->features &= ~NETIF_F_GRO; + + return 0; +} + static int ethtool_self_test(struct net_device *dev, char __user *useraddr) { struct ethtool_test test; @@ -937,6 +968,12 @@ int dev_ethtool(struct ifreq *ifr) case ETHTOOL_SGSO: rc = ethtool_set_gso(dev, useraddr); break; + case ETHTOOL_GGRO: + rc = ethtool_get_gro(dev, useraddr); + break; + case ETHTOOL_SGRO: + rc = ethtool_set_gro(dev, useraddr); + break; default: rc = -EOPNOTSUPP; }