aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel.garcia@free-electrons.com>2014-05-19 12:59:52 -0400
committerFugang Duan <b38611@freescale.com>2014-06-13 01:46:35 -0400
commit8978cf98adf987132974864dd4b8a2778a91acd3 (patch)
treefab2cd4608d6768f438f226d45e0666431b36eff
parent640fedeb1d4054c810d3cee510a7e772145c6ffe (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.h20
-rw-r--r--net/core/Makefile2
-rw-r--r--net/core/tso.c72
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
6struct tso_t {
7 int next_frag_idx;
8 void *data;
9 size_t size;
10 u16 ip_id;
11 u32 tcp_seq;
12};
13
14int tso_count_descs(struct sk_buff *skb);
15void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso,
16 int size, bool is_last);
17void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size);
18void 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
10obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ 10obj-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
14obj-$(CONFIG_XFRM) += flow.o 14obj-$(CONFIG_XFRM) += flow.o
15obj-y += net-sysfs.o 15obj-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 */
5int 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
11void 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
35void 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
52void 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}