1e876f208SEzequiel Garcia #include <net/ip.h> 2e876f208SEzequiel Garcia #include <net/tso.h> 3e876f208SEzequiel Garcia 4e876f208SEzequiel Garcia /* Calculate expected number of TX descriptors */ 5e876f208SEzequiel Garcia int tso_count_descs(struct sk_buff *skb) 6e876f208SEzequiel Garcia { 7e876f208SEzequiel Garcia /* The Marvell Way */ 8e876f208SEzequiel Garcia return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags; 9e876f208SEzequiel Garcia } 10e876f208SEzequiel Garcia 11e876f208SEzequiel Garcia void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, 12e876f208SEzequiel Garcia int size, bool is_last) 13e876f208SEzequiel Garcia { 14e876f208SEzequiel Garcia struct iphdr *iph; 15e876f208SEzequiel Garcia struct tcphdr *tcph; 16e876f208SEzequiel Garcia int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); 17e876f208SEzequiel Garcia int mac_hdr_len = skb_network_offset(skb); 18e876f208SEzequiel Garcia 19e876f208SEzequiel Garcia memcpy(hdr, skb->data, hdr_len); 20e876f208SEzequiel Garcia iph = (struct iphdr *)(hdr + mac_hdr_len); 21e876f208SEzequiel Garcia iph->id = htons(tso->ip_id); 22e876f208SEzequiel Garcia iph->tot_len = htons(size + hdr_len - mac_hdr_len); 23e876f208SEzequiel Garcia tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb)); 24e876f208SEzequiel Garcia tcph->seq = htonl(tso->tcp_seq); 25e876f208SEzequiel Garcia tso->ip_id++; 26e876f208SEzequiel Garcia 27e876f208SEzequiel Garcia if (!is_last) { 28e876f208SEzequiel Garcia /* Clear all special flags for not last packet */ 29e876f208SEzequiel Garcia tcph->psh = 0; 30e876f208SEzequiel Garcia tcph->fin = 0; 31e876f208SEzequiel Garcia tcph->rst = 0; 32e876f208SEzequiel Garcia } 33e876f208SEzequiel Garcia } 34e876f208SEzequiel Garcia 35e876f208SEzequiel Garcia void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size) 36e876f208SEzequiel Garcia { 37e876f208SEzequiel Garcia tso->tcp_seq += size; 38e876f208SEzequiel Garcia tso->size -= size; 39e876f208SEzequiel Garcia tso->data += size; 40e876f208SEzequiel Garcia 41e876f208SEzequiel Garcia if ((tso->size == 0) && 42e876f208SEzequiel Garcia (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { 43e876f208SEzequiel Garcia skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; 44e876f208SEzequiel Garcia 45e876f208SEzequiel Garcia /* Move to next segment */ 46e876f208SEzequiel Garcia tso->size = frag->size; 47e876f208SEzequiel Garcia tso->data = page_address(frag->page.p) + frag->page_offset; 48e876f208SEzequiel Garcia tso->next_frag_idx++; 49e876f208SEzequiel Garcia } 50e876f208SEzequiel Garcia } 51e876f208SEzequiel Garcia 52e876f208SEzequiel Garcia void tso_start(struct sk_buff *skb, struct tso_t *tso) 53e876f208SEzequiel Garcia { 54e876f208SEzequiel Garcia int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); 55e876f208SEzequiel Garcia 56e876f208SEzequiel Garcia tso->ip_id = ntohs(ip_hdr(skb)->id); 57e876f208SEzequiel Garcia tso->tcp_seq = ntohl(tcp_hdr(skb)->seq); 58e876f208SEzequiel Garcia tso->next_frag_idx = 0; 59e876f208SEzequiel Garcia 60e876f208SEzequiel Garcia /* Build first data */ 61e876f208SEzequiel Garcia tso->size = skb_headlen(skb) - hdr_len; 62e876f208SEzequiel Garcia tso->data = skb->data + hdr_len; 63e876f208SEzequiel Garcia if ((tso->size == 0) && 64e876f208SEzequiel Garcia (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { 65e876f208SEzequiel Garcia skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; 66e876f208SEzequiel Garcia 67e876f208SEzequiel Garcia /* Move to next segment */ 68e876f208SEzequiel Garcia tso->size = frag->size; 69e876f208SEzequiel Garcia tso->data = page_address(frag->page.p) + frag->page_offset; 70e876f208SEzequiel Garcia tso->next_frag_idx++; 71e876f208SEzequiel Garcia } 72e876f208SEzequiel Garcia } 73