aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/tile
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2012-07-11 14:08:21 -0400
committerChris Metcalf <cmetcalf@tilera.com>2012-07-18 15:03:00 -0400
commit8388546e7972ef8f1bf9c981139ad59cf5331820 (patch)
treee4efddd1dfb9d8ff718ada36ca994b4cbd3a3eb9 /drivers/net/ethernet/tile
parent9b4c341b1e3c207f57de3bf5f3c65845592dee89 (diff)
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>
Diffstat (limited to 'drivers/net/ethernet/tile')
-rw-r--r--drivers/net/ethernet/tile/tilegx.c36
1 files changed, 18 insertions, 18 deletions
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index a1c414f55114..ac4a904344f0 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -1333,11 +1333,12 @@ static s64 tile_net_equeue_try_reserve(struct net_device *dev,
1333static int tso_count_edescs(struct sk_buff *skb) 1333static int tso_count_edescs(struct sk_buff *skb)
1334{ 1334{
1335 struct skb_shared_info *sh = skb_shinfo(skb); 1335 struct skb_shared_info *sh = skb_shinfo(skb);
1336 unsigned int data_len = skb->data_len; 1336 unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
1337 unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
1337 unsigned int p_len = sh->gso_size; 1338 unsigned int p_len = sh->gso_size;
1338 long f_id = -1; /* id of the current fragment */ 1339 long f_id = -1; /* id of the current fragment */
1339 long f_size = -1; /* size of the current fragment */ 1340 long f_size = skb->hdr_len; /* size of the current fragment */
1340 long f_used = -1; /* bytes used from the current fragment */ 1341 long f_used = sh_len; /* bytes used from the current fragment */
1341 long n; /* size of the current piece of payload */ 1342 long n; /* size of the current piece of payload */
1342 int num_edescs = 0; 1343 int num_edescs = 0;
1343 int segment; 1344 int segment;
@@ -1382,13 +1383,14 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
1382 struct skb_shared_info *sh = skb_shinfo(skb); 1383 struct skb_shared_info *sh = skb_shinfo(skb);
1383 struct iphdr *ih; 1384 struct iphdr *ih;
1384 struct tcphdr *th; 1385 struct tcphdr *th;
1385 unsigned int data_len = skb->data_len; 1386 unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
1387 unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
1386 unsigned char *data = skb->data; 1388 unsigned char *data = skb->data;
1387 unsigned int ih_off, th_off, sh_len, p_len; 1389 unsigned int ih_off, th_off, p_len;
1388 unsigned int isum_seed, tsum_seed, id, seq; 1390 unsigned int isum_seed, tsum_seed, id, seq;
1389 long f_id = -1; /* id of the current fragment */ 1391 long f_id = -1; /* id of the current fragment */
1390 long f_size = -1; /* size of the current fragment */ 1392 long f_size = skb->hdr_len; /* size of the current fragment */
1391 long f_used = -1; /* bytes used from the current fragment */ 1393 long f_used = sh_len; /* bytes used from the current fragment */
1392 long n; /* size of the current piece of payload */ 1394 long n; /* size of the current piece of payload */
1393 int segment; 1395 int segment;
1394 1396
@@ -1397,14 +1399,13 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
1397 th = tcp_hdr(skb); 1399 th = tcp_hdr(skb);
1398 ih_off = skb_network_offset(skb); 1400 ih_off = skb_network_offset(skb);
1399 th_off = skb_transport_offset(skb); 1401 th_off = skb_transport_offset(skb);
1400 sh_len = th_off + tcp_hdrlen(skb);
1401 p_len = sh->gso_size; 1402 p_len = sh->gso_size;
1402 1403
1403 /* Set up seed values for IP and TCP csum and initialize id and seq. */ 1404 /* Set up seed values for IP and TCP csum and initialize id and seq. */
1404 isum_seed = ((0xFFFF - ih->check) + 1405 isum_seed = ((0xFFFF - ih->check) +
1405 (0xFFFF - ih->tot_len) + 1406 (0xFFFF - ih->tot_len) +
1406 (0xFFFF - ih->id)); 1407 (0xFFFF - ih->id));
1407 tsum_seed = th->check + (0xFFFF ^ htons(skb->len)); 1408 tsum_seed = th->check + (0xFFFF ^ htons(sh_len + data_len));
1408 id = ntohs(ih->id); 1409 id = ntohs(ih->id);
1409 seq = ntohl(th->seq); 1410 seq = ntohl(th->seq);
1410 1411
@@ -1476,21 +1477,22 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
1476{ 1477{
1477 struct tile_net_priv *priv = netdev_priv(dev); 1478 struct tile_net_priv *priv = netdev_priv(dev);
1478 struct skb_shared_info *sh = skb_shinfo(skb); 1479 struct skb_shared_info *sh = skb_shinfo(skb);
1479 unsigned int data_len = skb->data_len; 1480 unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
1481 unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
1480 unsigned int p_len = sh->gso_size; 1482 unsigned int p_len = sh->gso_size;
1481 gxio_mpipe_edesc_t edesc_head = { { 0 } }; 1483 gxio_mpipe_edesc_t edesc_head = { { 0 } };
1482 gxio_mpipe_edesc_t edesc_body = { { 0 } }; 1484 gxio_mpipe_edesc_t edesc_body = { { 0 } };
1483 long f_id = -1; /* id of the current fragment */ 1485 long f_id = -1; /* id of the current fragment */
1484 long f_size = -1; /* size of the current fragment */ 1486 long f_size = skb->hdr_len; /* size of the current fragment */
1485 long f_used = -1; /* bytes used from the current fragment */ 1487 long f_used = sh_len; /* bytes used from the current fragment */
1488 void *f_data = skb->data;
1486 long n; /* size of the current piece of payload */ 1489 long n; /* size of the current piece of payload */
1487 unsigned long tx_packets = 0, tx_bytes = 0; 1490 unsigned long tx_packets = 0, tx_bytes = 0;
1488 unsigned int csum_start, sh_len; 1491 unsigned int csum_start;
1489 int segment; 1492 int segment;
1490 1493
1491 /* Prepare to egress the headers: set up header edesc. */ 1494 /* Prepare to egress the headers: set up header edesc. */
1492 csum_start = skb_checksum_start_offset(skb); 1495 csum_start = skb_checksum_start_offset(skb);
1493 sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
1494 edesc_head.csum = 1; 1496 edesc_head.csum = 1;
1495 edesc_head.csum_start = csum_start; 1497 edesc_head.csum_start = csum_start;
1496 edesc_head.csum_dest = csum_start + skb->csum_offset; 1498 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,
1502 1504
1503 /* Egress all the edescs. */ 1505 /* Egress all the edescs. */
1504 for (segment = 0; segment < sh->gso_segs; segment++) { 1506 for (segment = 0; segment < sh->gso_segs; segment++) {
1505 void *va;
1506 unsigned char *buf; 1507 unsigned char *buf;
1507 unsigned int p_used = 0; 1508 unsigned int p_used = 0;
1508 1509
@@ -1521,10 +1522,9 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
1521 f_id++; 1522 f_id++;
1522 f_size = sh->frags[f_id].size; 1523 f_size = sh->frags[f_id].size;
1523 f_used = 0; 1524 f_used = 0;
1525 f_data = tile_net_frag_buf(&sh->frags[f_id]);
1524 } 1526 }
1525 1527
1526 va = tile_net_frag_buf(&sh->frags[f_id]) + f_used;
1527
1528 /* Use bytes from the current fragment. */ 1528 /* Use bytes from the current fragment. */
1529 n = p_len - p_used; 1529 n = p_len - p_used;
1530 if (n > f_size - f_used) 1530 if (n > f_size - f_used)
@@ -1533,7 +1533,7 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
1533 p_used += n; 1533 p_used += n;
1534 1534
1535 /* Egress a piece of the payload. */ 1535 /* Egress a piece of the payload. */
1536 edesc_body.va = va_to_tile_io_addr(va); 1536 edesc_body.va = va_to_tile_io_addr(f_data) + f_used;
1537 edesc_body.xfer_size = n; 1537 edesc_body.xfer_size = n;
1538 edesc_body.bound = !(p_used < p_len); 1538 edesc_body.bound = !(p_used < p_len);
1539 gxio_mpipe_equeue_put_at(equeue, edesc_body, slot); 1539 gxio_mpipe_equeue_put_at(equeue, edesc_body, slot);