Commit 3da3fff8 authored by Chris Metcalf's avatar Chris Metcalf Committed by David S. Miller

tilegx: fix some issues in the SW TSO support

This change correctly computes the header length and data length in
the fragments to avoid a bug where we would end up with extremely
slow performance.  Also adopt use of skb_frag_size() accessor.
Signed-off-by: default avatarChris Metcalf <cmetcalf@tilera.com>
Cc: stable@vger.kernel.org [v3.6]
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f8295ec2
...@@ -1334,11 +1334,11 @@ static int tso_count_edescs(struct sk_buff *skb) ...@@ -1334,11 +1334,11 @@ 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 sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); 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 data_len = skb->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 = skb->hdr_len; /* size of the current fragment */ long f_size = skb_headlen(skb) - sh_len; /* current fragment size */
long f_used = sh_len; /* bytes used from the current fragment */ long f_used = 0; /* 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;
...@@ -1353,7 +1353,7 @@ static int tso_count_edescs(struct sk_buff *skb) ...@@ -1353,7 +1353,7 @@ static int tso_count_edescs(struct sk_buff *skb)
/* Advance as needed. */ /* Advance as needed. */
while (f_used >= f_size) { while (f_used >= f_size) {
f_id++; f_id++;
f_size = sh->frags[f_id].size; f_size = skb_frag_size(&sh->frags[f_id]);
f_used = 0; f_used = 0;
} }
...@@ -1384,13 +1384,13 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, ...@@ -1384,13 +1384,13 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
struct iphdr *ih; struct iphdr *ih;
struct tcphdr *th; struct tcphdr *th;
unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); 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 data_len = skb->len - sh_len;
unsigned char *data = skb->data; unsigned char *data = skb->data;
unsigned int ih_off, th_off, 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 = skb->hdr_len; /* size of the current fragment */ long f_size = skb_headlen(skb) - sh_len; /* current fragment size */
long f_used = sh_len; /* bytes used from the current fragment */ long f_used = 0; /* 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;
...@@ -1405,7 +1405,7 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, ...@@ -1405,7 +1405,7 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
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(sh_len + data_len)); tsum_seed = th->check + (0xFFFF ^ htons(skb->len));
id = ntohs(ih->id); id = ntohs(ih->id);
seq = ntohl(th->seq); seq = ntohl(th->seq);
...@@ -1444,7 +1444,7 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, ...@@ -1444,7 +1444,7 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
/* Advance as needed. */ /* Advance as needed. */
while (f_used >= f_size) { while (f_used >= f_size) {
f_id++; f_id++;
f_size = sh->frags[f_id].size; f_size = skb_frag_size(&sh->frags[f_id]);
f_used = 0; f_used = 0;
} }
...@@ -1478,14 +1478,14 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue, ...@@ -1478,14 +1478,14 @@ 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 sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); 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 data_len = skb->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 = skb->hdr_len; /* size of the current fragment */ long f_size = skb_headlen(skb) - sh_len; /* current fragment size */
long f_used = sh_len; /* bytes used from the current fragment */ long f_used = 0; /* bytes used from the current fragment */
void *f_data = skb->data; void *f_data = skb->data + sh_len;
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; unsigned int csum_start;
...@@ -1516,15 +1516,18 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue, ...@@ -1516,15 +1516,18 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
/* Egress the payload. */ /* Egress the payload. */
while (p_used < p_len) { while (p_used < p_len) {
void *va;
/* Advance as needed. */ /* Advance as needed. */
while (f_used >= f_size) { while (f_used >= f_size) {
f_id++; f_id++;
f_size = sh->frags[f_id].size; f_size = skb_frag_size(&sh->frags[f_id]);
f_used = 0;
f_data = tile_net_frag_buf(&sh->frags[f_id]); f_data = tile_net_frag_buf(&sh->frags[f_id]);
f_used = 0;
} }
va = f_data + 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 +1536,7 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue, ...@@ -1533,7 +1536,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(f_data) + f_used; edesc_body.va = va_to_tile_io_addr(va);
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment