diff options
-rw-r--r-- | drivers/net/mv643xx_eth.c | 95 |
1 files changed, 47 insertions, 48 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 94c13be292a3..9522c449ccea 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -699,79 +699,74 @@ static inline __be16 sum16_as_be(__sum16 sum) | |||
699 | return (__force __be16)sum; | 699 | return (__force __be16)sum; |
700 | } | 700 | } |
701 | 701 | ||
702 | static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) | 702 | static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) |
703 | { | 703 | { |
704 | struct mv643xx_eth_private *mp = txq_to_mp(txq); | 704 | struct mv643xx_eth_private *mp = txq_to_mp(txq); |
705 | int nr_frags = skb_shinfo(skb)->nr_frags; | 705 | int nr_frags = skb_shinfo(skb)->nr_frags; |
706 | int tx_index; | 706 | int tx_index; |
707 | struct tx_desc *desc; | 707 | struct tx_desc *desc; |
708 | u32 cmd_sts; | 708 | u32 cmd_sts; |
709 | u16 l4i_chk; | ||
709 | int length; | 710 | int length; |
710 | 711 | ||
711 | cmd_sts = TX_FIRST_DESC | GEN_CRC | BUFFER_OWNED_BY_DMA; | 712 | cmd_sts = TX_FIRST_DESC | GEN_CRC | BUFFER_OWNED_BY_DMA; |
712 | 713 | l4i_chk = 0; | |
713 | tx_index = txq_alloc_desc_index(txq); | ||
714 | desc = &txq->tx_desc_area[tx_index]; | ||
715 | |||
716 | if (nr_frags) { | ||
717 | txq_submit_frag_skb(txq, skb); | ||
718 | length = skb_headlen(skb); | ||
719 | } else { | ||
720 | cmd_sts |= ZERO_PADDING | TX_LAST_DESC | TX_ENABLE_INTERRUPT; | ||
721 | length = skb->len; | ||
722 | } | ||
723 | |||
724 | desc->byte_cnt = length; | ||
725 | desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); | ||
726 | 714 | ||
727 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 715 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
728 | int mac_hdr_len; | 716 | int tag_bytes; |
729 | 717 | ||
730 | BUG_ON(skb->protocol != htons(ETH_P_IP) && | 718 | BUG_ON(skb->protocol != htons(ETH_P_IP) && |
731 | skb->protocol != htons(ETH_P_8021Q)); | 719 | skb->protocol != htons(ETH_P_8021Q)); |
732 | 720 | ||
733 | cmd_sts |= GEN_TCP_UDP_CHECKSUM | | 721 | tag_bytes = (void *)ip_hdr(skb) - (void *)skb->data - ETH_HLEN; |
734 | GEN_IP_V4_CHECKSUM | | 722 | if (unlikely(tag_bytes & ~12)) { |
735 | ip_hdr(skb)->ihl << TX_IHL_SHIFT; | 723 | if (skb_checksum_help(skb) == 0) |
724 | goto no_csum; | ||
725 | kfree_skb(skb); | ||
726 | return 1; | ||
727 | } | ||
736 | 728 | ||
737 | mac_hdr_len = (void *)ip_hdr(skb) - (void *)skb->data; | 729 | if (tag_bytes & 4) |
738 | switch (mac_hdr_len - ETH_HLEN) { | ||
739 | case 0: | ||
740 | break; | ||
741 | case 4: | ||
742 | cmd_sts |= MAC_HDR_EXTRA_4_BYTES; | ||
743 | break; | ||
744 | case 8: | ||
745 | cmd_sts |= MAC_HDR_EXTRA_8_BYTES; | ||
746 | break; | ||
747 | case 12: | ||
748 | cmd_sts |= MAC_HDR_EXTRA_4_BYTES; | 730 | cmd_sts |= MAC_HDR_EXTRA_4_BYTES; |
731 | if (tag_bytes & 8) | ||
749 | cmd_sts |= MAC_HDR_EXTRA_8_BYTES; | 732 | cmd_sts |= MAC_HDR_EXTRA_8_BYTES; |
750 | break; | 733 | |
751 | default: | 734 | cmd_sts |= GEN_TCP_UDP_CHECKSUM | |
752 | if (net_ratelimit()) | 735 | GEN_IP_V4_CHECKSUM | |
753 | dev_printk(KERN_ERR, &txq_to_mp(txq)->dev->dev, | 736 | ip_hdr(skb)->ihl << TX_IHL_SHIFT; |
754 | "mac header length is %d?!\n", mac_hdr_len); | ||
755 | break; | ||
756 | } | ||
757 | 737 | ||
758 | switch (ip_hdr(skb)->protocol) { | 738 | switch (ip_hdr(skb)->protocol) { |
759 | case IPPROTO_UDP: | 739 | case IPPROTO_UDP: |
760 | cmd_sts |= UDP_FRAME; | 740 | cmd_sts |= UDP_FRAME; |
761 | desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check)); | 741 | l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check)); |
762 | break; | 742 | break; |
763 | case IPPROTO_TCP: | 743 | case IPPROTO_TCP: |
764 | desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check)); | 744 | l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check)); |
765 | break; | 745 | break; |
766 | default: | 746 | default: |
767 | BUG(); | 747 | BUG(); |
768 | } | 748 | } |
769 | } else { | 749 | } else { |
750 | no_csum: | ||
770 | /* Errata BTS #50, IHL must be 5 if no HW checksum */ | 751 | /* Errata BTS #50, IHL must be 5 if no HW checksum */ |
771 | cmd_sts |= 5 << TX_IHL_SHIFT; | 752 | cmd_sts |= 5 << TX_IHL_SHIFT; |
772 | desc->l4i_chk = 0; | ||
773 | } | 753 | } |
774 | 754 | ||
755 | tx_index = txq_alloc_desc_index(txq); | ||
756 | desc = &txq->tx_desc_area[tx_index]; | ||
757 | |||
758 | if (nr_frags) { | ||
759 | txq_submit_frag_skb(txq, skb); | ||
760 | length = skb_headlen(skb); | ||
761 | } else { | ||
762 | cmd_sts |= ZERO_PADDING | TX_LAST_DESC | TX_ENABLE_INTERRUPT; | ||
763 | length = skb->len; | ||
764 | } | ||
765 | |||
766 | desc->l4i_chk = l4i_chk; | ||
767 | desc->byte_cnt = length; | ||
768 | desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); | ||
769 | |||
775 | __skb_queue_tail(&txq->tx_skb, skb); | 770 | __skb_queue_tail(&txq->tx_skb, skb); |
776 | 771 | ||
777 | /* ensure all other descriptors are written before first cmd_sts */ | 772 | /* ensure all other descriptors are written before first cmd_sts */ |
@@ -786,6 +781,8 @@ static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) | |||
786 | txq_enable(txq); | 781 | txq_enable(txq); |
787 | 782 | ||
788 | txq->tx_desc_count += nr_frags + 1; | 783 | txq->tx_desc_count += nr_frags + 1; |
784 | |||
785 | return 0; | ||
789 | } | 786 | } |
790 | 787 | ||
791 | static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) | 788 | static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) |
@@ -794,7 +791,6 @@ static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) | |||
794 | int queue; | 791 | int queue; |
795 | struct tx_queue *txq; | 792 | struct tx_queue *txq; |
796 | struct netdev_queue *nq; | 793 | struct netdev_queue *nq; |
797 | int entries_left; | ||
798 | 794 | ||
799 | queue = skb_get_queue_mapping(skb); | 795 | queue = skb_get_queue_mapping(skb); |
800 | txq = mp->txq + queue; | 796 | txq = mp->txq + queue; |
@@ -815,14 +811,17 @@ static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) | |||
815 | return NETDEV_TX_OK; | 811 | return NETDEV_TX_OK; |
816 | } | 812 | } |
817 | 813 | ||
818 | txq_submit_skb(txq, skb); | 814 | if (!txq_submit_skb(txq, skb)) { |
819 | txq->tx_bytes += skb->len; | 815 | int entries_left; |
820 | txq->tx_packets++; | 816 | |
821 | dev->trans_start = jiffies; | 817 | txq->tx_bytes += skb->len; |
818 | txq->tx_packets++; | ||
819 | dev->trans_start = jiffies; | ||
822 | 820 | ||
823 | entries_left = txq->tx_ring_size - txq->tx_desc_count; | 821 | entries_left = txq->tx_ring_size - txq->tx_desc_count; |
824 | if (entries_left < MAX_SKB_FRAGS + 1) | 822 | if (entries_left < MAX_SKB_FRAGS + 1) |
825 | netif_tx_stop_queue(nq); | 823 | netif_tx_stop_queue(nq); |
824 | } | ||
826 | 825 | ||
827 | return NETDEV_TX_OK; | 826 | return NETDEV_TX_OK; |
828 | } | 827 | } |