diff options
author | Ezequiel Garcia <ezequiel.garcia@free-electrons.com> | 2014-05-19 12:59:52 -0400 |
---|---|---|
committer | Fugang Duan <b38611@freescale.com> | 2014-06-13 01:46:35 -0400 |
commit | 8978cf98adf987132974864dd4b8a2778a91acd3 (patch) | |
tree | fab2cd4608d6768f438f226d45e0666431b36eff | |
parent | 640fedeb1d4054c810d3cee510a7e772145c6ffe (diff) |
net: Add a software TSO helper API
Although the implementation probably needs a lot of work, this initial API
allows to implement software TSO in mvneta and mv643xx_eth drivers in a not
so intrusive way.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
-rw-r--r-- | include/net/tso.h | 20 | ||||
-rw-r--r-- | net/core/Makefile | 2 | ||||
-rw-r--r-- | net/core/tso.c | 72 |
3 files changed, 93 insertions, 1 deletions
diff --git a/include/net/tso.h b/include/net/tso.h new file mode 100644 index 000000000000..47e5444f7d15 --- /dev/null +++ b/include/net/tso.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef _TSO_H | ||
2 | #define _TSO_H | ||
3 | |||
4 | #include <net/ip.h> | ||
5 | |||
6 | struct tso_t { | ||
7 | int next_frag_idx; | ||
8 | void *data; | ||
9 | size_t size; | ||
10 | u16 ip_id; | ||
11 | u32 tcp_seq; | ||
12 | }; | ||
13 | |||
14 | int tso_count_descs(struct sk_buff *skb); | ||
15 | void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, | ||
16 | int size, bool is_last); | ||
17 | void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size); | ||
18 | void tso_start(struct sk_buff *skb, struct tso_t *tso); | ||
19 | |||
20 | #endif /* _TSO_H */ | ||
diff --git a/net/core/Makefile b/net/core/Makefile index b33b996f5dd6..843385bd547c 100644 --- a/net/core/Makefile +++ b/net/core/Makefile | |||
@@ -9,7 +9,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o | |||
9 | 9 | ||
10 | obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ | 10 | obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ |
11 | neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ | 11 | neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ |
12 | sock_diag.o dev_ioctl.o | 12 | sock_diag.o dev_ioctl.o tso.o |
13 | 13 | ||
14 | obj-$(CONFIG_XFRM) += flow.o | 14 | obj-$(CONFIG_XFRM) += flow.o |
15 | obj-y += net-sysfs.o | 15 | obj-y += net-sysfs.o |
diff --git a/net/core/tso.c b/net/core/tso.c new file mode 100644 index 000000000000..097821dd3a8c --- /dev/null +++ b/net/core/tso.c | |||
@@ -0,0 +1,72 @@ | |||
1 | #include <net/ip.h> | ||
2 | #include <net/tso.h> | ||
3 | |||
4 | /* Calculate expected number of TX descriptors */ | ||
5 | int tso_count_descs(struct sk_buff *skb) | ||
6 | { | ||
7 | /* The Marvell Way */ | ||
8 | return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags; | ||
9 | } | ||
10 | |||
11 | void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, | ||
12 | int size, bool is_last) | ||
13 | { | ||
14 | struct iphdr *iph; | ||
15 | struct tcphdr *tcph; | ||
16 | int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); | ||
17 | int mac_hdr_len = skb_network_offset(skb); | ||
18 | |||
19 | memcpy(hdr, skb->data, hdr_len); | ||
20 | iph = (struct iphdr *)(hdr + mac_hdr_len); | ||
21 | iph->id = htons(tso->ip_id); | ||
22 | iph->tot_len = htons(size + hdr_len - mac_hdr_len); | ||
23 | tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb)); | ||
24 | tcph->seq = htonl(tso->tcp_seq); | ||
25 | tso->ip_id++; | ||
26 | |||
27 | if (!is_last) { | ||
28 | /* Clear all special flags for not last packet */ | ||
29 | tcph->psh = 0; | ||
30 | tcph->fin = 0; | ||
31 | tcph->rst = 0; | ||
32 | } | ||
33 | } | ||
34 | |||
35 | void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size) | ||
36 | { | ||
37 | tso->tcp_seq += size; | ||
38 | tso->size -= size; | ||
39 | tso->data += size; | ||
40 | |||
41 | if ((tso->size == 0) && | ||
42 | (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { | ||
43 | skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; | ||
44 | |||
45 | /* Move to next segment */ | ||
46 | tso->size = frag->size; | ||
47 | tso->data = page_address(frag->page.p) + frag->page_offset; | ||
48 | tso->next_frag_idx++; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | void tso_start(struct sk_buff *skb, struct tso_t *tso) | ||
53 | { | ||
54 | int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); | ||
55 | |||
56 | tso->ip_id = ntohs(ip_hdr(skb)->id); | ||
57 | tso->tcp_seq = ntohl(tcp_hdr(skb)->seq); | ||
58 | tso->next_frag_idx = 0; | ||
59 | |||
60 | /* Build first data */ | ||
61 | tso->size = skb_headlen(skb) - hdr_len; | ||
62 | tso->data = skb->data + hdr_len; | ||
63 | if ((tso->size == 0) && | ||
64 | (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { | ||
65 | skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; | ||
66 | |||
67 | /* Move to next segment */ | ||
68 | tso->size = frag->size; | ||
69 | tso->data = page_address(frag->page.p) + frag->page_offset; | ||
70 | tso->next_frag_idx++; | ||
71 | } | ||
72 | } | ||