tilegx net driver: handle payload data not in frags
The original driver implementation assumed that for TSO, all the payload data would be in the frags. This isn't always true; change the driver to support payload data at skb->data between "skb_transport_offset(skb) + tcp_hdrlen(skb)" and "skb->hdr_len", followed by the data in the frags. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
This commit is contained in:
parent
9b4c341b1e
commit
8388546e79
|
@ -1333,11 +1333,12 @@ static s64 tile_net_equeue_try_reserve(struct net_device *dev,
|
||||||
static int tso_count_edescs(struct sk_buff *skb)
|
static int tso_count_edescs(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct skb_shared_info *sh = skb_shinfo(skb);
|
struct skb_shared_info *sh = skb_shinfo(skb);
|
||||||
unsigned int data_len = skb->data_len;
|
unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||||
|
unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
|
||||||
unsigned int p_len = sh->gso_size;
|
unsigned int p_len = sh->gso_size;
|
||||||
long f_id = -1; /* id of the current fragment */
|
long f_id = -1; /* id of the current fragment */
|
||||||
long f_size = -1; /* size of the current fragment */
|
long f_size = skb->hdr_len; /* size of the current fragment */
|
||||||
long f_used = -1; /* bytes used from the current fragment */
|
long f_used = sh_len; /* bytes used from the current fragment */
|
||||||
long n; /* size of the current piece of payload */
|
long n; /* size of the current piece of payload */
|
||||||
int num_edescs = 0;
|
int num_edescs = 0;
|
||||||
int segment;
|
int segment;
|
||||||
|
@ -1382,13 +1383,14 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
|
||||||
struct skb_shared_info *sh = skb_shinfo(skb);
|
struct skb_shared_info *sh = skb_shinfo(skb);
|
||||||
struct iphdr *ih;
|
struct iphdr *ih;
|
||||||
struct tcphdr *th;
|
struct tcphdr *th;
|
||||||
unsigned int data_len = skb->data_len;
|
unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||||
|
unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
|
||||||
unsigned char *data = skb->data;
|
unsigned char *data = skb->data;
|
||||||
unsigned int ih_off, th_off, sh_len, p_len;
|
unsigned int ih_off, th_off, p_len;
|
||||||
unsigned int isum_seed, tsum_seed, id, seq;
|
unsigned int isum_seed, tsum_seed, id, seq;
|
||||||
long f_id = -1; /* id of the current fragment */
|
long f_id = -1; /* id of the current fragment */
|
||||||
long f_size = -1; /* size of the current fragment */
|
long f_size = skb->hdr_len; /* size of the current fragment */
|
||||||
long f_used = -1; /* bytes used from the current fragment */
|
long f_used = sh_len; /* bytes used from the current fragment */
|
||||||
long n; /* size of the current piece of payload */
|
long n; /* size of the current piece of payload */
|
||||||
int segment;
|
int segment;
|
||||||
|
|
||||||
|
@ -1397,14 +1399,13 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
|
||||||
th = tcp_hdr(skb);
|
th = tcp_hdr(skb);
|
||||||
ih_off = skb_network_offset(skb);
|
ih_off = skb_network_offset(skb);
|
||||||
th_off = skb_transport_offset(skb);
|
th_off = skb_transport_offset(skb);
|
||||||
sh_len = th_off + tcp_hdrlen(skb);
|
|
||||||
p_len = sh->gso_size;
|
p_len = sh->gso_size;
|
||||||
|
|
||||||
/* Set up seed values for IP and TCP csum and initialize id and seq. */
|
/* Set up seed values for IP and TCP csum and initialize id and seq. */
|
||||||
isum_seed = ((0xFFFF - ih->check) +
|
isum_seed = ((0xFFFF - ih->check) +
|
||||||
(0xFFFF - ih->tot_len) +
|
(0xFFFF - ih->tot_len) +
|
||||||
(0xFFFF - ih->id));
|
(0xFFFF - ih->id));
|
||||||
tsum_seed = th->check + (0xFFFF ^ htons(skb->len));
|
tsum_seed = th->check + (0xFFFF ^ htons(sh_len + data_len));
|
||||||
id = ntohs(ih->id);
|
id = ntohs(ih->id);
|
||||||
seq = ntohl(th->seq);
|
seq = ntohl(th->seq);
|
||||||
|
|
||||||
|
@ -1476,21 +1477,22 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
|
||||||
{
|
{
|
||||||
struct tile_net_priv *priv = netdev_priv(dev);
|
struct tile_net_priv *priv = netdev_priv(dev);
|
||||||
struct skb_shared_info *sh = skb_shinfo(skb);
|
struct skb_shared_info *sh = skb_shinfo(skb);
|
||||||
unsigned int data_len = skb->data_len;
|
unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||||
|
unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
|
||||||
unsigned int p_len = sh->gso_size;
|
unsigned int p_len = sh->gso_size;
|
||||||
gxio_mpipe_edesc_t edesc_head = { { 0 } };
|
gxio_mpipe_edesc_t edesc_head = { { 0 } };
|
||||||
gxio_mpipe_edesc_t edesc_body = { { 0 } };
|
gxio_mpipe_edesc_t edesc_body = { { 0 } };
|
||||||
long f_id = -1; /* id of the current fragment */
|
long f_id = -1; /* id of the current fragment */
|
||||||
long f_size = -1; /* size of the current fragment */
|
long f_size = skb->hdr_len; /* size of the current fragment */
|
||||||
long f_used = -1; /* bytes used from the current fragment */
|
long f_used = sh_len; /* bytes used from the current fragment */
|
||||||
|
void *f_data = skb->data;
|
||||||
long n; /* size of the current piece of payload */
|
long n; /* size of the current piece of payload */
|
||||||
unsigned long tx_packets = 0, tx_bytes = 0;
|
unsigned long tx_packets = 0, tx_bytes = 0;
|
||||||
unsigned int csum_start, sh_len;
|
unsigned int csum_start;
|
||||||
int segment;
|
int segment;
|
||||||
|
|
||||||
/* Prepare to egress the headers: set up header edesc. */
|
/* Prepare to egress the headers: set up header edesc. */
|
||||||
csum_start = skb_checksum_start_offset(skb);
|
csum_start = skb_checksum_start_offset(skb);
|
||||||
sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
|
||||||
edesc_head.csum = 1;
|
edesc_head.csum = 1;
|
||||||
edesc_head.csum_start = csum_start;
|
edesc_head.csum_start = csum_start;
|
||||||
edesc_head.csum_dest = csum_start + skb->csum_offset;
|
edesc_head.csum_dest = csum_start + skb->csum_offset;
|
||||||
|
@ -1502,7 +1504,6 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
|
||||||
|
|
||||||
/* Egress all the edescs. */
|
/* Egress all the edescs. */
|
||||||
for (segment = 0; segment < sh->gso_segs; segment++) {
|
for (segment = 0; segment < sh->gso_segs; segment++) {
|
||||||
void *va;
|
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
unsigned int p_used = 0;
|
unsigned int p_used = 0;
|
||||||
|
|
||||||
|
@ -1521,10 +1522,9 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
|
||||||
f_id++;
|
f_id++;
|
||||||
f_size = sh->frags[f_id].size;
|
f_size = sh->frags[f_id].size;
|
||||||
f_used = 0;
|
f_used = 0;
|
||||||
|
f_data = tile_net_frag_buf(&sh->frags[f_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
va = tile_net_frag_buf(&sh->frags[f_id]) + f_used;
|
|
||||||
|
|
||||||
/* Use bytes from the current fragment. */
|
/* Use bytes from the current fragment. */
|
||||||
n = p_len - p_used;
|
n = p_len - p_used;
|
||||||
if (n > f_size - f_used)
|
if (n > f_size - f_used)
|
||||||
|
@ -1533,7 +1533,7 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
|
||||||
p_used += n;
|
p_used += n;
|
||||||
|
|
||||||
/* Egress a piece of the payload. */
|
/* Egress a piece of the payload. */
|
||||||
edesc_body.va = va_to_tile_io_addr(va);
|
edesc_body.va = va_to_tile_io_addr(f_data) + f_used;
|
||||||
edesc_body.xfer_size = n;
|
edesc_body.xfer_size = n;
|
||||||
edesc_body.bound = !(p_used < p_len);
|
edesc_body.bound = !(p_used < p_len);
|
||||||
gxio_mpipe_equeue_put_at(equeue, edesc_body, slot);
|
gxio_mpipe_equeue_put_at(equeue, edesc_body, slot);
|
||||||
|
|
Loading…
Reference in New Issue