-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Ezequiel Garcia
authored and
David S. Miller
committed
May 22, 2014
1 parent
8af750d
commit e876f20
Showing
3 changed files
with
93 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#ifndef _TSO_H | ||
#define _TSO_H | ||
|
||
#include <net/ip.h> | ||
|
||
struct tso_t { | ||
int next_frag_idx; | ||
void *data; | ||
size_t size; | ||
u16 ip_id; | ||
u32 tcp_seq; | ||
}; | ||
|
||
int tso_count_descs(struct sk_buff *skb); | ||
void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, | ||
int size, bool is_last); | ||
void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size); | ||
void tso_start(struct sk_buff *skb, struct tso_t *tso); | ||
|
||
#endif /* _TSO_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#include <net/ip.h> | ||
#include <net/tso.h> | ||
|
||
/* Calculate expected number of TX descriptors */ | ||
int tso_count_descs(struct sk_buff *skb) | ||
{ | ||
/* The Marvell Way */ | ||
return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags; | ||
} | ||
|
||
void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, | ||
int size, bool is_last) | ||
{ | ||
struct iphdr *iph; | ||
struct tcphdr *tcph; | ||
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); | ||
int mac_hdr_len = skb_network_offset(skb); | ||
|
||
memcpy(hdr, skb->data, hdr_len); | ||
iph = (struct iphdr *)(hdr + mac_hdr_len); | ||
iph->id = htons(tso->ip_id); | ||
iph->tot_len = htons(size + hdr_len - mac_hdr_len); | ||
tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb)); | ||
tcph->seq = htonl(tso->tcp_seq); | ||
tso->ip_id++; | ||
|
||
if (!is_last) { | ||
/* Clear all special flags for not last packet */ | ||
tcph->psh = 0; | ||
tcph->fin = 0; | ||
tcph->rst = 0; | ||
} | ||
} | ||
|
||
void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size) | ||
{ | ||
tso->tcp_seq += size; | ||
tso->size -= size; | ||
tso->data += size; | ||
|
||
if ((tso->size == 0) && | ||
(tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { | ||
skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; | ||
|
||
/* Move to next segment */ | ||
tso->size = frag->size; | ||
tso->data = page_address(frag->page.p) + frag->page_offset; | ||
tso->next_frag_idx++; | ||
} | ||
} | ||
|
||
void tso_start(struct sk_buff *skb, struct tso_t *tso) | ||
{ | ||
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); | ||
|
||
tso->ip_id = ntohs(ip_hdr(skb)->id); | ||
tso->tcp_seq = ntohl(tcp_hdr(skb)->seq); | ||
tso->next_frag_idx = 0; | ||
|
||
/* Build first data */ | ||
tso->size = skb_headlen(skb) - hdr_len; | ||
tso->data = skb->data + hdr_len; | ||
if ((tso->size == 0) && | ||
(tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { | ||
skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; | ||
|
||
/* Move to next segment */ | ||
tso->size = frag->size; | ||
tso->data = page_address(frag->page.p) + frag->page_offset; | ||
tso->next_frag_idx++; | ||
} | ||
} |