aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ethtool.h2
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--include/net/sock.h4
-rw-r--r--net/bridge/br_if.c17
-rw-r--r--net/core/ethtool.c29
5 files changed, 47 insertions, 6 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index cf2abeca92a0..c6310aef5ab0 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -411,6 +411,8 @@ struct ethtool_ops {
411#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */ 411#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */
412#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */ 412#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */
413#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ 413#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */
414#define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */
415#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */
414 416
415/* compatibility with older code */ 417/* compatibility with older code */
416#define SPARC_ETH_GSET ETHTOOL_GSET 418#define SPARC_ETH_GSET ETHTOOL_GSET
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index b4eae18390cc..bc747e5d7138 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -308,6 +308,7 @@ struct net_device
308#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */ 308#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */
309#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */ 309#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */
310#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ 310#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
311#define NETIF_F_GSO 2048 /* Enable software GSO. */
311#define NETIF_F_LLTX 4096 /* LockLess TX */ 312#define NETIF_F_LLTX 4096 /* LockLess TX */
312 313
313 /* Segmentation offload features */ 314 /* Segmentation offload features */
diff --git a/include/net/sock.h b/include/net/sock.h
index d10dfecb6cbd..a897f05de3b5 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1030,9 +1030,13 @@ static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
1030{ 1030{
1031 __sk_dst_set(sk, dst); 1031 __sk_dst_set(sk, dst);
1032 sk->sk_route_caps = dst->dev->features; 1032 sk->sk_route_caps = dst->dev->features;
1033 if (sk->sk_route_caps & NETIF_F_GSO)
1034 sk->sk_route_caps |= NETIF_F_TSO;
1033 if (sk->sk_route_caps & NETIF_F_TSO) { 1035 if (sk->sk_route_caps & NETIF_F_TSO) {
1034 if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len) 1036 if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
1035 sk->sk_route_caps &= ~NETIF_F_TSO; 1037 sk->sk_route_caps &= ~NETIF_F_TSO;
1038 else
1039 sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
1036 } 1040 }
1037} 1041}
1038 1042
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index fdec773f5b52..07956ecf545e 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -376,15 +376,20 @@ void br_features_recompute(struct net_bridge *br)
376 features = br->feature_mask & ~NETIF_F_ALL_CSUM; 376 features = br->feature_mask & ~NETIF_F_ALL_CSUM;
377 377
378 list_for_each_entry(p, &br->port_list, list) { 378 list_for_each_entry(p, &br->port_list, list) {
379 if (checksum & NETIF_F_NO_CSUM && 379 unsigned long feature = p->dev->features;
380 !(p->dev->features & NETIF_F_NO_CSUM)) 380
381 if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
381 checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM; 382 checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
382 if (checksum & NETIF_F_HW_CSUM && 383 if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
383 !(p->dev->features & NETIF_F_HW_CSUM))
384 checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM; 384 checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
385 if (!(p->dev->features & NETIF_F_IP_CSUM)) 385 if (!(feature & NETIF_F_IP_CSUM))
386 checksum = 0; 386 checksum = 0;
387 features &= p->dev->features; 387
388 if (feature & NETIF_F_GSO)
389 feature |= NETIF_F_TSO;
390 feature |= NETIF_F_GSO;
391
392 features &= feature;
388 } 393 }
389 394
390 br->dev->features = features | checksum | NETIF_F_LLTX; 395 br->dev->features = features | checksum | NETIF_F_LLTX;
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 33ce7ed6afc6..27ce1683caf5 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -614,6 +614,29 @@ static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
614 return dev->ethtool_ops->set_ufo(dev, edata.data); 614 return dev->ethtool_ops->set_ufo(dev, edata.data);
615} 615}
616 616
617static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
618{
619 struct ethtool_value edata = { ETHTOOL_GGSO };
620
621 edata.data = dev->features & NETIF_F_GSO;
622 if (copy_to_user(useraddr, &edata, sizeof(edata)))
623 return -EFAULT;
624 return 0;
625}
626
627static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
628{
629 struct ethtool_value edata;
630
631 if (copy_from_user(&edata, useraddr, sizeof(edata)))
632 return -EFAULT;
633 if (edata.data)
634 dev->features |= NETIF_F_GSO;
635 else
636 dev->features &= ~NETIF_F_GSO;
637 return 0;
638}
639
617static int ethtool_self_test(struct net_device *dev, char __user *useraddr) 640static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
618{ 641{
619 struct ethtool_test test; 642 struct ethtool_test test;
@@ -905,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr)
905 case ETHTOOL_SUFO: 928 case ETHTOOL_SUFO:
906 rc = ethtool_set_ufo(dev, useraddr); 929 rc = ethtool_set_ufo(dev, useraddr);
907 break; 930 break;
931 case ETHTOOL_GGSO:
932 rc = ethtool_get_gso(dev, useraddr);
933 break;
934 case ETHTOOL_SGSO:
935 rc = ethtool_set_gso(dev, useraddr);
936 break;
908 default: 937 default:
909 rc = -EOPNOTSUPP; 938 rc = -EOPNOTSUPP;
910 } 939 }