Skip to content
Snippets Groups Projects
Commit 37c3185a authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[NET]: Added GSO toggle


This patch adds a generic segmentation offload toggle that can be turned
on/off for each net device.  For now it only supports in TCPv4.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f4c50d99
No related branches found
No related tags found
No related merge requests found
...@@ -411,6 +411,8 @@ struct ethtool_ops { ...@@ -411,6 +411,8 @@ struct ethtool_ops {
#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */ #define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */
#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */ #define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */
#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ #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) */
/* compatibility with older code */ /* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET #define SPARC_ETH_GSET ETHTOOL_GSET
......
...@@ -308,6 +308,7 @@ struct net_device ...@@ -308,6 +308,7 @@ struct net_device
#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */ #define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */
#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */ #define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */
#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
#define NETIF_F_GSO 2048 /* Enable software GSO. */
#define NETIF_F_LLTX 4096 /* LockLess TX */ #define NETIF_F_LLTX 4096 /* LockLess TX */
/* Segmentation offload features */ /* Segmentation offload features */
......
...@@ -1030,9 +1030,13 @@ static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst) ...@@ -1030,9 +1030,13 @@ static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
{ {
__sk_dst_set(sk, dst); __sk_dst_set(sk, dst);
sk->sk_route_caps = dst->dev->features; sk->sk_route_caps = dst->dev->features;
if (sk->sk_route_caps & NETIF_F_GSO)
sk->sk_route_caps |= NETIF_F_TSO;
if (sk->sk_route_caps & NETIF_F_TSO) { if (sk->sk_route_caps & NETIF_F_TSO) {
if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len) if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
sk->sk_route_caps &= ~NETIF_F_TSO; sk->sk_route_caps &= ~NETIF_F_TSO;
else
sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
} }
} }
......
...@@ -376,15 +376,20 @@ void br_features_recompute(struct net_bridge *br) ...@@ -376,15 +376,20 @@ void br_features_recompute(struct net_bridge *br)
features = br->feature_mask & ~NETIF_F_ALL_CSUM; features = br->feature_mask & ~NETIF_F_ALL_CSUM;
list_for_each_entry(p, &br->port_list, list) { list_for_each_entry(p, &br->port_list, list) {
if (checksum & NETIF_F_NO_CSUM && unsigned long feature = p->dev->features;
!(p->dev->features & NETIF_F_NO_CSUM))
if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM; checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
if (checksum & NETIF_F_HW_CSUM && if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
!(p->dev->features & NETIF_F_HW_CSUM))
checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM; checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
if (!(p->dev->features & NETIF_F_IP_CSUM)) if (!(feature & NETIF_F_IP_CSUM))
checksum = 0; checksum = 0;
features &= p->dev->features;
if (feature & NETIF_F_GSO)
feature |= NETIF_F_TSO;
feature |= NETIF_F_GSO;
features &= feature;
} }
br->dev->features = features | checksum | NETIF_F_LLTX; br->dev->features = features | checksum | NETIF_F_LLTX;
......
...@@ -614,6 +614,29 @@ static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) ...@@ -614,6 +614,29 @@ static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
return dev->ethtool_ops->set_ufo(dev, edata.data); return dev->ethtool_ops->set_ufo(dev, edata.data);
} }
static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
{
struct ethtool_value edata = { ETHTOOL_GGSO };
edata.data = dev->features & NETIF_F_GSO;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
{
struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
if (edata.data)
dev->features |= NETIF_F_GSO;
else
dev->features &= ~NETIF_F_GSO;
return 0;
}
static int ethtool_self_test(struct net_device *dev, char __user *useraddr) static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
{ {
struct ethtool_test test; struct ethtool_test test;
...@@ -905,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr) ...@@ -905,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr)
case ETHTOOL_SUFO: case ETHTOOL_SUFO:
rc = ethtool_set_ufo(dev, useraddr); rc = ethtool_set_ufo(dev, useraddr);
break; break;
case ETHTOOL_GGSO:
rc = ethtool_get_gso(dev, useraddr);
break;
case ETHTOOL_SGSO:
rc = ethtool_set_gso(dev, useraddr);
break;
default: default:
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment