diff options
author | Chris Metcalf <cmetcalf@tilera.com> | 2012-07-11 14:08:21 -0400 |
---|---|---|
committer | Chris Metcalf <cmetcalf@tilera.com> | 2012-07-18 15:03:00 -0400 |
commit | 8388546e7972ef8f1bf9c981139ad59cf5331820 (patch) | |
tree | e4efddd1dfb9d8ff718ada36ca994b4cbd3a3eb9 | |
parent | 9b4c341b1e3c207f57de3bf5f3c65845592dee89 (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>
-rw-r--r-- | drivers/net/ethernet/tile/tilegx.c | 36 |
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, | |||
1333 | static int tso_count_edescs(struct sk_buff *skb) | 1333 | static 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); |