+ pci_dma_sync_single_for_device(pdev,
+ dmaaddr,
+ len,
+ PCI_DMA_TODEVICE);
+
+ txdesc->dw[0] = 0;
+ txdesc->dw[1] = 0;
+ txdesc->desc2.flags = TXFLAG_OWN;
+ txdesc->desc2.flags |= (hidma) ? TXFLAG_64BIT : 0;
+ txdesc->desc2.datalen = cpu_to_le16(len);
+ txdesc->desc2.bufaddrh = cpu_to_le32((__u64)dmaaddr >> 32);
+ txdesc->desc2.bufaddrl = cpu_to_le32(
+ (__u64)dmaaddr & 0xFFFFFFFFUL);
+
+ txbi->mapping = dmaaddr;
+ txbi->len = len;
+}
+
+static void
+jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
+{
+ struct jme_ring *txring = &(jme->txring[0]);
+ struct txdesc *txdesc = txring->desc, *ctxdesc;
+ struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
+ u8 hidma = jme->dev->features & NETIF_F_HIGHDMA;
+ int i, nr_frags = skb_shinfo(skb)->nr_frags;
+ int mask = jme->tx_ring_mask;
+ struct skb_frag_struct *frag;
+ u32 len;
+
+ for (i = 0 ; i < nr_frags ; ++i) {
+ frag = &skb_shinfo(skb)->frags[i];
+ ctxdesc = txdesc + ((idx + i + 2) & (mask));
+ ctxbi = txbi + ((idx + i + 2) & (mask));
+
+ jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, frag->page,
+ frag->page_offset, frag->size, hidma);
+ }
+
+ len = skb_is_nonlinear(skb) ? skb_headlen(skb) : skb->len;
+ ctxdesc = txdesc + ((idx + 1) & (mask));
+ ctxbi = txbi + ((idx + 1) & (mask));
+ jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, virt_to_page(skb->data),
+ offset_in_page(skb->data), len, hidma);
+
+}
+
+static int
+jme_expand_header(struct jme_adapter *jme, struct sk_buff *skb)
+{
+ if (unlikely(
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
+ skb_shinfo(skb)->tso_size
+#else
+ skb_shinfo(skb)->gso_size
+#endif
+ && skb_header_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) {
+ dev_kfree_skb(skb);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+jme_tx_tso(struct sk_buff *skb, __le16 *mss, u8 *flags)
+{
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
+ *mss = cpu_to_le16(skb_shinfo(skb)->tso_size << TXDESC_MSS_SHIFT);
+#else
+ *mss = cpu_to_le16(skb_shinfo(skb)->gso_size << TXDESC_MSS_SHIFT);
+#endif
+ if (*mss) {
+ *flags |= TXFLAG_LSEN;
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph = ip_hdr(skb);
+
+ iph->check = 0;
+ tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+ iph->daddr, 0,
+ IPPROTO_TCP,
+ 0);
+ } else {
+ struct ipv6hdr *ip6h = ipv6_hdr(skb);
+
+ tcp_hdr(skb)->check = ~csum_ipv6_magic(&ip6h->saddr,
+ &ip6h->daddr, 0,
+ IPPROTO_TCP,
+ 0);
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags)
+{
+#ifdef CHECKSUM_PARTIAL
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+#else
+ if (skb->ip_summed == CHECKSUM_HW)
+#endif
+ {
+ u8 ip_proto;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
+ if (skb->protocol == htons(ETH_P_IP))
+ ip_proto = ip_hdr(skb)->protocol;
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ ip_proto = ipv6_hdr(skb)->nexthdr;
+ else
+ ip_proto = 0;
+#else
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ ip_proto = ip_hdr(skb)->protocol;
+ break;
+ case htons(ETH_P_IPV6):
+ ip_proto = ipv6_hdr(skb)->nexthdr;
+ break;
+ default:
+ ip_proto = 0;
+ break;
+ }