diff options
| author | David Woodhouse <dwmw2@infradead.org> | 2015-09-24 06:38:22 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-09-27 01:38:34 -0400 |
| commit | 8b7a7048220f86547db31de0abe1ea6dd2cfa892 (patch) | |
| tree | d2fc6cc721822b02e326569b2d011bd906a6842b | |
| parent | 5a58f227790faded5a3ef6075f3ddd65093e0f86 (diff) | |
8139cp: Fix GSO MSS handling
When fixing the TSO support I noticed we just mask ->gso_size with the
MSSMask value and don't care about the consequences.
Provide a .ndo_features_check() method which drops the NETIF_F_TSO
feature for any skb which would exceed the maximum, and thus forces it
to be segmented by software.
Then we can stop the masking in cp_start_xmit(), and just WARN if the
maximum is exceeded, which should now never happen.
Finally, Francois Romieu noticed that we didn't even have the right
value for MSSMask anyway; it should be 0x7ff (11 bits) not 0xfff.
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/realtek/8139cp.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index e5173f33428b..deae10d7426d 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c | |||
| @@ -175,7 +175,7 @@ enum { | |||
| 175 | LastFrag = (1 << 28), /* Final segment of a packet */ | 175 | LastFrag = (1 << 28), /* Final segment of a packet */ |
| 176 | LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ | 176 | LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ |
| 177 | MSSShift = 16, /* MSS value position */ | 177 | MSSShift = 16, /* MSS value position */ |
| 178 | MSSMask = 0xfff, /* MSS value: 11 bits */ | 178 | MSSMask = 0x7ff, /* MSS value: 11 bits */ |
| 179 | TxError = (1 << 23), /* Tx error summary */ | 179 | TxError = (1 << 23), /* Tx error summary */ |
| 180 | RxError = (1 << 20), /* Rx error summary */ | 180 | RxError = (1 << 20), /* Rx error summary */ |
| 181 | IPCS = (1 << 18), /* Calculate IP checksum */ | 181 | IPCS = (1 << 18), /* Calculate IP checksum */ |
| @@ -754,10 +754,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, | |||
| 754 | eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; | 754 | eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; |
| 755 | mss = skb_shinfo(skb)->gso_size; | 755 | mss = skb_shinfo(skb)->gso_size; |
| 756 | 756 | ||
| 757 | if (mss > MSSMask) { | ||
| 758 | WARN_ONCE(1, "Net bug: GSO size %d too large for 8139CP\n", | ||
| 759 | mss); | ||
| 760 | goto out_dma_error; | ||
| 761 | } | ||
| 762 | |||
| 757 | opts2 = cpu_to_le32(cp_tx_vlan_tag(skb)); | 763 | opts2 = cpu_to_le32(cp_tx_vlan_tag(skb)); |
| 758 | opts1 = DescOwn; | 764 | opts1 = DescOwn; |
| 759 | if (mss) | 765 | if (mss) |
| 760 | opts1 |= LargeSend | ((mss & MSSMask) << MSSShift); | 766 | opts1 |= LargeSend | (mss << MSSShift); |
| 761 | else if (skb->ip_summed == CHECKSUM_PARTIAL) { | 767 | else if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| 762 | const struct iphdr *ip = ip_hdr(skb); | 768 | const struct iphdr *ip = ip_hdr(skb); |
| 763 | if (ip->protocol == IPPROTO_TCP) | 769 | if (ip->protocol == IPPROTO_TCP) |
| @@ -1852,6 +1858,15 @@ static void cp_set_d3_state (struct cp_private *cp) | |||
| 1852 | pci_set_power_state (cp->pdev, PCI_D3hot); | 1858 | pci_set_power_state (cp->pdev, PCI_D3hot); |
| 1853 | } | 1859 | } |
| 1854 | 1860 | ||
| 1861 | static netdev_features_t cp_features_check(struct sk_buff *skb, | ||
| 1862 | struct net_device *dev, | ||
| 1863 | netdev_features_t features) | ||
| 1864 | { | ||
| 1865 | if (skb_shinfo(skb)->gso_size > MSSMask) | ||
| 1866 | features &= ~NETIF_F_TSO; | ||
| 1867 | |||
| 1868 | return vlan_features_check(skb, features); | ||
| 1869 | } | ||
| 1855 | static const struct net_device_ops cp_netdev_ops = { | 1870 | static const struct net_device_ops cp_netdev_ops = { |
| 1856 | .ndo_open = cp_open, | 1871 | .ndo_open = cp_open, |
| 1857 | .ndo_stop = cp_close, | 1872 | .ndo_stop = cp_close, |
| @@ -1864,6 +1879,7 @@ static const struct net_device_ops cp_netdev_ops = { | |||
| 1864 | .ndo_tx_timeout = cp_tx_timeout, | 1879 | .ndo_tx_timeout = cp_tx_timeout, |
| 1865 | .ndo_set_features = cp_set_features, | 1880 | .ndo_set_features = cp_set_features, |
| 1866 | .ndo_change_mtu = cp_change_mtu, | 1881 | .ndo_change_mtu = cp_change_mtu, |
| 1882 | .ndo_features_check = cp_features_check, | ||
| 1867 | 1883 | ||
| 1868 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1884 | #ifdef CONFIG_NET_POLL_CONTROLLER |
| 1869 | .ndo_poll_controller = cp_poll_controller, | 1885 | .ndo_poll_controller = cp_poll_controller, |
