.. | .. |
---|
6 | 6 | #include <asm/unaligned.h> |
---|
7 | 7 | |
---|
8 | 8 | /* Calculate expected number of TX descriptors */ |
---|
9 | | -int tso_count_descs(struct sk_buff *skb) |
---|
| 9 | +int tso_count_descs(const struct sk_buff *skb) |
---|
10 | 10 | { |
---|
11 | 11 | /* The Marvell Way */ |
---|
12 | 12 | return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags; |
---|
13 | 13 | } |
---|
14 | 14 | EXPORT_SYMBOL(tso_count_descs); |
---|
15 | 15 | |
---|
16 | | -void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, |
---|
| 16 | +void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso, |
---|
17 | 17 | int size, bool is_last) |
---|
18 | 18 | { |
---|
19 | | - struct tcphdr *tcph; |
---|
20 | | - int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); |
---|
| 19 | + int hdr_len = skb_transport_offset(skb) + tso->tlen; |
---|
21 | 20 | int mac_hdr_len = skb_network_offset(skb); |
---|
22 | 21 | |
---|
23 | 22 | memcpy(hdr, skb->data, hdr_len); |
---|
.. | .. |
---|
30 | 29 | } else { |
---|
31 | 30 | struct ipv6hdr *iph = (void *)(hdr + mac_hdr_len); |
---|
32 | 31 | |
---|
33 | | - iph->payload_len = htons(size + tcp_hdrlen(skb)); |
---|
| 32 | + iph->payload_len = htons(size + tso->tlen); |
---|
34 | 33 | } |
---|
35 | | - tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb)); |
---|
36 | | - put_unaligned_be32(tso->tcp_seq, &tcph->seq); |
---|
| 34 | + hdr += skb_transport_offset(skb); |
---|
| 35 | + if (tso->tlen != sizeof(struct udphdr)) { |
---|
| 36 | + struct tcphdr *tcph = (struct tcphdr *)hdr; |
---|
37 | 37 | |
---|
38 | | - if (!is_last) { |
---|
39 | | - /* Clear all special flags for not last packet */ |
---|
40 | | - tcph->psh = 0; |
---|
41 | | - tcph->fin = 0; |
---|
42 | | - tcph->rst = 0; |
---|
| 38 | + put_unaligned_be32(tso->tcp_seq, &tcph->seq); |
---|
| 39 | + |
---|
| 40 | + if (!is_last) { |
---|
| 41 | + /* Clear all special flags for not last packet */ |
---|
| 42 | + tcph->psh = 0; |
---|
| 43 | + tcph->fin = 0; |
---|
| 44 | + tcph->rst = 0; |
---|
| 45 | + } |
---|
| 46 | + } else { |
---|
| 47 | + struct udphdr *uh = (struct udphdr *)hdr; |
---|
| 48 | + |
---|
| 49 | + uh->len = htons(sizeof(*uh) + size); |
---|
43 | 50 | } |
---|
44 | 51 | } |
---|
45 | 52 | EXPORT_SYMBOL(tso_build_hdr); |
---|
46 | 53 | |
---|
47 | | -void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size) |
---|
| 54 | +void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size) |
---|
48 | 55 | { |
---|
49 | | - tso->tcp_seq += size; |
---|
| 56 | + tso->tcp_seq += size; /* not worth avoiding this operation for UDP */ |
---|
50 | 57 | tso->size -= size; |
---|
51 | 58 | tso->data += size; |
---|
52 | 59 | |
---|
.. | .. |
---|
55 | 62 | skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; |
---|
56 | 63 | |
---|
57 | 64 | /* Move to next segment */ |
---|
58 | | - tso->size = frag->size; |
---|
59 | | - tso->data = page_address(frag->page.p) + frag->page_offset; |
---|
| 65 | + tso->size = skb_frag_size(frag); |
---|
| 66 | + tso->data = skb_frag_address(frag); |
---|
60 | 67 | tso->next_frag_idx++; |
---|
61 | 68 | } |
---|
62 | 69 | } |
---|
63 | 70 | EXPORT_SYMBOL(tso_build_data); |
---|
64 | 71 | |
---|
65 | | -void tso_start(struct sk_buff *skb, struct tso_t *tso) |
---|
| 72 | +int tso_start(struct sk_buff *skb, struct tso_t *tso) |
---|
66 | 73 | { |
---|
67 | | - int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); |
---|
| 74 | + int tlen = skb_is_gso_tcp(skb) ? tcp_hdrlen(skb) : sizeof(struct udphdr); |
---|
| 75 | + int hdr_len = skb_transport_offset(skb) + tlen; |
---|
68 | 76 | |
---|
| 77 | + tso->tlen = tlen; |
---|
69 | 78 | tso->ip_id = ntohs(ip_hdr(skb)->id); |
---|
70 | | - tso->tcp_seq = ntohl(tcp_hdr(skb)->seq); |
---|
| 79 | + tso->tcp_seq = (tlen != sizeof(struct udphdr)) ? ntohl(tcp_hdr(skb)->seq) : 0; |
---|
71 | 80 | tso->next_frag_idx = 0; |
---|
72 | 81 | tso->ipv6 = vlan_get_protocol(skb) == htons(ETH_P_IPV6); |
---|
73 | 82 | |
---|
.. | .. |
---|
79 | 88 | skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; |
---|
80 | 89 | |
---|
81 | 90 | /* Move to next segment */ |
---|
82 | | - tso->size = frag->size; |
---|
83 | | - tso->data = page_address(frag->page.p) + frag->page_offset; |
---|
| 91 | + tso->size = skb_frag_size(frag); |
---|
| 92 | + tso->data = skb_frag_address(frag); |
---|
84 | 93 | tso->next_frag_idx++; |
---|
85 | 94 | } |
---|
| 95 | + return hdr_len; |
---|
86 | 96 | } |
---|
87 | 97 | EXPORT_SYMBOL(tso_start); |
---|