diff options
-rw-r--r-- | drivers/net/8139cp.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index d639cb8dc461..a7573dd92f26 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c | |||
@@ -186,6 +186,9 @@ enum { | |||
186 | RingEnd = (1 << 30), /* End of descriptor ring */ | 186 | RingEnd = (1 << 30), /* End of descriptor ring */ |
187 | FirstFrag = (1 << 29), /* First segment of a packet */ | 187 | FirstFrag = (1 << 29), /* First segment of a packet */ |
188 | LastFrag = (1 << 28), /* Final segment of a packet */ | 188 | LastFrag = (1 << 28), /* Final segment of a packet */ |
189 | LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ | ||
190 | MSSShift = 16, /* MSS value position */ | ||
191 | MSSMask = 0xfff, /* MSS value: 11 bits */ | ||
189 | TxError = (1 << 23), /* Tx error summary */ | 192 | TxError = (1 << 23), /* Tx error summary */ |
190 | RxError = (1 << 20), /* Rx error summary */ | 193 | RxError = (1 << 20), /* Rx error summary */ |
191 | IPCS = (1 << 18), /* Calculate IP checksum */ | 194 | IPCS = (1 << 18), /* Calculate IP checksum */ |
@@ -749,10 +752,11 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) | |||
749 | { | 752 | { |
750 | struct cp_private *cp = netdev_priv(dev); | 753 | struct cp_private *cp = netdev_priv(dev); |
751 | unsigned entry; | 754 | unsigned entry; |
752 | u32 eor; | 755 | u32 eor, flags; |
753 | #if CP_VLAN_TAG_USED | 756 | #if CP_VLAN_TAG_USED |
754 | u32 vlan_tag = 0; | 757 | u32 vlan_tag = 0; |
755 | #endif | 758 | #endif |
759 | int mss = 0; | ||
756 | 760 | ||
757 | spin_lock_irq(&cp->lock); | 761 | spin_lock_irq(&cp->lock); |
758 | 762 | ||
@@ -772,6 +776,9 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) | |||
772 | 776 | ||
773 | entry = cp->tx_head; | 777 | entry = cp->tx_head; |
774 | eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; | 778 | eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; |
779 | if (dev->features & NETIF_F_TSO) | ||
780 | mss = skb_shinfo(skb)->tso_size; | ||
781 | |||
775 | if (skb_shinfo(skb)->nr_frags == 0) { | 782 | if (skb_shinfo(skb)->nr_frags == 0) { |
776 | struct cp_desc *txd = &cp->tx_ring[entry]; | 783 | struct cp_desc *txd = &cp->tx_ring[entry]; |
777 | u32 len; | 784 | u32 len; |
@@ -783,21 +790,21 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) | |||
783 | txd->addr = cpu_to_le64(mapping); | 790 | txd->addr = cpu_to_le64(mapping); |
784 | wmb(); | 791 | wmb(); |
785 | 792 | ||
786 | if (skb->ip_summed == CHECKSUM_HW) { | 793 | flags = eor | len | DescOwn | FirstFrag | LastFrag; |
794 | |||
795 | if (mss) | ||
796 | flags |= LargeSend | ((mss & MSSMask) << MSSShift); | ||
797 | else if (skb->ip_summed == CHECKSUM_HW) { | ||
787 | const struct iphdr *ip = skb->nh.iph; | 798 | const struct iphdr *ip = skb->nh.iph; |
788 | if (ip->protocol == IPPROTO_TCP) | 799 | if (ip->protocol == IPPROTO_TCP) |
789 | txd->opts1 = cpu_to_le32(eor | len | DescOwn | | 800 | flags |= IPCS | TCPCS; |
790 | FirstFrag | LastFrag | | ||
791 | IPCS | TCPCS); | ||
792 | else if (ip->protocol == IPPROTO_UDP) | 801 | else if (ip->protocol == IPPROTO_UDP) |
793 | txd->opts1 = cpu_to_le32(eor | len | DescOwn | | 802 | flags |= IPCS | UDPCS; |
794 | FirstFrag | LastFrag | | ||
795 | IPCS | UDPCS); | ||
796 | else | 803 | else |
797 | BUG(); | 804 | BUG(); |
798 | } else | 805 | } |
799 | txd->opts1 = cpu_to_le32(eor | len | DescOwn | | 806 | |
800 | FirstFrag | LastFrag); | 807 | txd->opts1 = cpu_to_le32(flags); |
801 | wmb(); | 808 | wmb(); |
802 | 809 | ||
803 | cp->tx_skb[entry].skb = skb; | 810 | cp->tx_skb[entry].skb = skb; |
@@ -836,16 +843,19 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) | |||
836 | len, PCI_DMA_TODEVICE); | 843 | len, PCI_DMA_TODEVICE); |
837 | eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; | 844 | eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; |
838 | 845 | ||
839 | if (skb->ip_summed == CHECKSUM_HW) { | 846 | ctrl = eor | len | DescOwn; |
840 | ctrl = eor | len | DescOwn | IPCS; | 847 | |
848 | if (mss) | ||
849 | ctrl |= LargeSend | | ||
850 | ((mss & MSSMask) << MSSShift); | ||
851 | else if (skb->ip_summed == CHECKSUM_HW) { | ||
841 | if (ip->protocol == IPPROTO_TCP) | 852 | if (ip->protocol == IPPROTO_TCP) |
842 | ctrl |= TCPCS; | 853 | ctrl |= IPCS | TCPCS; |
843 | else if (ip->protocol == IPPROTO_UDP) | 854 | else if (ip->protocol == IPPROTO_UDP) |
844 | ctrl |= UDPCS; | 855 | ctrl |= IPCS | UDPCS; |
845 | else | 856 | else |
846 | BUG(); | 857 | BUG(); |
847 | } else | 858 | } |
848 | ctrl = eor | len | DescOwn; | ||
849 | 859 | ||
850 | if (frag == skb_shinfo(skb)->nr_frags - 1) | 860 | if (frag == skb_shinfo(skb)->nr_frags - 1) |
851 | ctrl |= LastFrag; | 861 | ctrl |= LastFrag; |
@@ -1538,6 +1548,8 @@ static struct ethtool_ops cp_ethtool_ops = { | |||
1538 | .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ | 1548 | .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ |
1539 | .get_sg = ethtool_op_get_sg, | 1549 | .get_sg = ethtool_op_get_sg, |
1540 | .set_sg = ethtool_op_set_sg, | 1550 | .set_sg = ethtool_op_set_sg, |
1551 | .get_tso = ethtool_op_get_tso, | ||
1552 | .set_tso = ethtool_op_set_tso, | ||
1541 | .get_regs = cp_get_regs, | 1553 | .get_regs = cp_get_regs, |
1542 | .get_wol = cp_get_wol, | 1554 | .get_wol = cp_get_wol, |
1543 | .set_wol = cp_set_wol, | 1555 | .set_wol = cp_set_wol, |
@@ -1768,6 +1780,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1768 | if (pci_using_dac) | 1780 | if (pci_using_dac) |
1769 | dev->features |= NETIF_F_HIGHDMA; | 1781 | dev->features |= NETIF_F_HIGHDMA; |
1770 | 1782 | ||
1783 | #if 0 /* disabled by default until verified */ | ||
1784 | dev->features |= NETIF_F_TSO; | ||
1785 | #endif | ||
1786 | |||
1771 | dev->irq = pdev->irq; | 1787 | dev->irq = pdev->irq; |
1772 | 1788 | ||
1773 | rc = register_netdev(dev); | 1789 | rc = register_netdev(dev); |