+ if (!skb_shinfo(skb)->nr_frags) {
+ if (skb->ip_summed != CHECKSUM_HW) {
+ /* Errata BTS #50, IHL must be 5 if no HW checksum */
+ pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
+ ETH_TX_FIRST_DESC |
+ ETH_TX_LAST_DESC |
+ 5 << ETH_TX_IHL_SHIFT;
+ pkt_info.l4i_chk = 0;
+ } else {
+ pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
+ ETH_TX_FIRST_DESC |
+ ETH_TX_LAST_DESC |
+ ETH_GEN_TCP_UDP_CHECKSUM |
+ ETH_GEN_IP_V_4_CHECKSUM |
+ skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
+ /* CPU already calculated pseudo header checksum. */
+ if ((skb->protocol == ETH_P_IP) &&
+ (skb->nh.iph->protocol == IPPROTO_UDP) ) {
+ pkt_info.cmd_sts |= ETH_UDP_FRAME;
+ pkt_info.l4i_chk = skb->h.uh->check;
+ } else if ((skb->protocol == ETH_P_IP) &&
+ (skb->nh.iph->protocol == IPPROTO_TCP))
+ pkt_info.l4i_chk = skb->h.th->check;
+ else {
+ printk(KERN_ERR
+ "%s: chksum proto != IPv4 TCP or UDP\n",
+ dev->name);
+ spin_unlock_irqrestore(&mp->lock, flags);
+ return 1;
+ }
+ }
+ pkt_info.byte_cnt = skb->len;
+ pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ pkt_info.return_info = skb;
+ status = eth_port_send(mp, &pkt_info);
+ if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
+ printk(KERN_ERR "%s: Error on transmitting packet\n",
+ dev->name);
+ stats->tx_bytes += pkt_info.byte_cnt;
+ } else {
+ unsigned int frag;
+
+ /* first frag which is skb header */
+ pkt_info.byte_cnt = skb_headlen(skb);
+ pkt_info.buf_ptr = dma_map_single(NULL, skb->data,
+ skb_headlen(skb),
+ DMA_TO_DEVICE);
+ pkt_info.l4i_chk = 0;
+ pkt_info.return_info = 0;
+
+ if (skb->ip_summed != CHECKSUM_HW)
+ /* Errata BTS #50, IHL must be 5 if no HW checksum */
+ pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
+ 5 << ETH_TX_IHL_SHIFT;
+ else {
+ pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
+ ETH_GEN_TCP_UDP_CHECKSUM |
+ ETH_GEN_IP_V_4_CHECKSUM |
+ skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
+ /* CPU already calculated pseudo header checksum. */
+ if ((skb->protocol == ETH_P_IP) &&
+ (skb->nh.iph->protocol == IPPROTO_UDP)) {
+ pkt_info.cmd_sts |= ETH_UDP_FRAME;
+ pkt_info.l4i_chk = skb->h.uh->check;
+ } else if ((skb->protocol == ETH_P_IP) &&
+ (skb->nh.iph->protocol == IPPROTO_TCP))
+ pkt_info.l4i_chk = skb->h.th->check;
+ else {
+ printk(KERN_ERR
+ "%s: chksum proto != IPv4 TCP or UDP\n",
+ dev->name);
+ spin_unlock_irqrestore(&mp->lock, flags);
+ return 1;
+ }
+ }
+
+ status = eth_port_send(mp, &pkt_info);
+ if (status != ETH_OK) {
+ if ((status == ETH_ERROR))
+ printk(KERN_ERR
+ "%s: Error on transmitting packet\n",
+ dev->name);
+ if (status == ETH_QUEUE_FULL)
+ printk("Error on Queue Full \n");
+ if (status == ETH_QUEUE_LAST_RESOURCE)
+ printk("Tx resource error \n");
+ }
+ stats->tx_bytes += pkt_info.byte_cnt;
+
+ /* Check for the remaining frags */
+ for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+ skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+ pkt_info.l4i_chk = 0x0000;
+ pkt_info.cmd_sts = 0x00000000;
+
+ /* Last Frag enables interrupt and frees the skb */
+ if (frag == (skb_shinfo(skb)->nr_frags - 1)) {
+ pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
+ ETH_TX_LAST_DESC;
+ pkt_info.return_info = skb;
+ } else {
+ pkt_info.return_info = 0;
+ }
+ pkt_info.l4i_chk = 0;
+ pkt_info.byte_cnt = this_frag->size;
+
+ pkt_info.buf_ptr = dma_map_page(NULL, this_frag->page,
+ this_frag->page_offset,
+ this_frag->size,
+ DMA_TO_DEVICE);
+
+ status = eth_port_send(mp, &pkt_info);
+
+ if (status != ETH_OK) {
+ if ((status == ETH_ERROR))
+ printk(KERN_ERR "%s: Error on "
+ "transmitting packet\n",
+ dev->name);
+
+ if (status == ETH_QUEUE_LAST_RESOURCE)
+ printk("Tx resource error \n");
+
+ if (status == ETH_QUEUE_FULL)
+ printk("Queue is full \n");
+ }
+ stats->tx_bytes += pkt_info.byte_cnt;
+ }
+ }
+#else
+ spin_lock_irqsave(&mp->lock, flags);