Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -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
+1 −0
Original line number Original line Diff line number Diff line
@@ -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 */
+4 −0
Original line number Original line Diff line number Diff line
@@ -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;
	}
	}
}
}


+11 −6
Original line number Original line Diff line number Diff line
@@ -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;
+29 −0
Original line number Original line Diff line number Diff line
@@ -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)
	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;
	}
	}