diff options
author | Chris Metcalf <cmetcalf@tilera.com> | 2013-08-01 11:36:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-01 17:35:50 -0400 |
commit | 2c7d04a9c4c3cb7212bb7c66989f0f4a35ed6a26 (patch) | |
tree | 68c7cf10ee895e47291de0e9dd8c85a5b5768ed0 /drivers/net/ethernet/tile | |
parent | f3286a3af89d6db7a488f3e8f02b98d67d50f00c (diff) |
tile: support TSO for IPv6 in tilegx network driver
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/tile')
-rw-r--r-- | drivers/net/ethernet/tile/tilegx.c | 44 |
1 files changed, 29 insertions, 15 deletions
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index b80a91f0561f..6d94d58d4287 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/io.h> | 36 | #include <linux/io.h> |
37 | #include <linux/ctype.h> | 37 | #include <linux/ctype.h> |
38 | #include <linux/ip.h> | 38 | #include <linux/ip.h> |
39 | #include <linux/ipv6.h> | ||
39 | #include <linux/tcp.h> | 40 | #include <linux/tcp.h> |
40 | 41 | ||
41 | #include <asm/checksum.h> | 42 | #include <asm/checksum.h> |
@@ -1512,20 +1513,20 @@ static int tso_count_edescs(struct sk_buff *skb) | |||
1512 | return num_edescs; | 1513 | return num_edescs; |
1513 | } | 1514 | } |
1514 | 1515 | ||
1515 | /* Prepare modified copies of the skbuff headers. | 1516 | /* Prepare modified copies of the skbuff headers. */ |
1516 | * FIXME: add support for IPv6. | ||
1517 | */ | ||
1518 | static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, | 1517 | static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, |
1519 | s64 slot) | 1518 | s64 slot) |
1520 | { | 1519 | { |
1521 | struct skb_shared_info *sh = skb_shinfo(skb); | 1520 | struct skb_shared_info *sh = skb_shinfo(skb); |
1522 | struct iphdr *ih; | 1521 | struct iphdr *ih; |
1522 | struct ipv6hdr *ih6; | ||
1523 | struct tcphdr *th; | 1523 | struct tcphdr *th; |
1524 | unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); | 1524 | unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); |
1525 | unsigned int data_len = skb->len - sh_len; | 1525 | unsigned int data_len = skb->len - sh_len; |
1526 | unsigned char *data = skb->data; | 1526 | unsigned char *data = skb->data; |
1527 | unsigned int ih_off, th_off, p_len; | 1527 | unsigned int ih_off, th_off, p_len; |
1528 | unsigned int isum_seed, tsum_seed, id, seq; | 1528 | unsigned int isum_seed, tsum_seed, id, seq; |
1529 | int is_ipv6; | ||
1529 | long f_id = -1; /* id of the current fragment */ | 1530 | long f_id = -1; /* id of the current fragment */ |
1530 | long f_size = skb_headlen(skb) - sh_len; /* current fragment size */ | 1531 | long f_size = skb_headlen(skb) - sh_len; /* current fragment size */ |
1531 | long f_used = 0; /* bytes used from the current fragment */ | 1532 | long f_used = 0; /* bytes used from the current fragment */ |
@@ -1533,18 +1534,24 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, | |||
1533 | int segment; | 1534 | int segment; |
1534 | 1535 | ||
1535 | /* Locate original headers and compute various lengths. */ | 1536 | /* Locate original headers and compute various lengths. */ |
1536 | ih = ip_hdr(skb); | 1537 | is_ipv6 = skb_is_gso_v6(skb); |
1538 | if (is_ipv6) { | ||
1539 | ih6 = ipv6_hdr(skb); | ||
1540 | ih_off = skb_network_offset(skb); | ||
1541 | } else { | ||
1542 | ih = ip_hdr(skb); | ||
1543 | ih_off = skb_network_offset(skb); | ||
1544 | isum_seed = ((0xFFFF - ih->check) + | ||
1545 | (0xFFFF - ih->tot_len) + | ||
1546 | (0xFFFF - ih->id)); | ||
1547 | id = ntohs(ih->id); | ||
1548 | } | ||
1549 | |||
1537 | th = tcp_hdr(skb); | 1550 | th = tcp_hdr(skb); |
1538 | ih_off = skb_network_offset(skb); | ||
1539 | th_off = skb_transport_offset(skb); | 1551 | th_off = skb_transport_offset(skb); |
1540 | p_len = sh->gso_size; | 1552 | p_len = sh->gso_size; |
1541 | 1553 | ||
1542 | /* Set up seed values for IP and TCP csum and initialize id and seq. */ | ||
1543 | isum_seed = ((0xFFFF - ih->check) + | ||
1544 | (0xFFFF - ih->tot_len) + | ||
1545 | (0xFFFF - ih->id)); | ||
1546 | tsum_seed = th->check + (0xFFFF ^ htons(skb->len)); | 1554 | tsum_seed = th->check + (0xFFFF ^ htons(skb->len)); |
1547 | id = ntohs(ih->id); | ||
1548 | seq = ntohl(th->seq); | 1555 | seq = ntohl(th->seq); |
1549 | 1556 | ||
1550 | /* Prepare all the headers. */ | 1557 | /* Prepare all the headers. */ |
@@ -1558,11 +1565,17 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, | |||
1558 | memcpy(buf, data, sh_len); | 1565 | memcpy(buf, data, sh_len); |
1559 | 1566 | ||
1560 | /* Update copied ip header. */ | 1567 | /* Update copied ip header. */ |
1561 | ih = (struct iphdr *)(buf + ih_off); | 1568 | if (is_ipv6) { |
1562 | ih->tot_len = htons(sh_len + p_len - ih_off); | 1569 | ih6 = (struct ipv6hdr *)(buf + ih_off); |
1563 | ih->id = htons(id); | 1570 | ih6->payload_len = htons(sh_len + p_len - ih_off - |
1564 | ih->check = csum_long(isum_seed + ih->tot_len + | 1571 | sizeof(*ih6)); |
1565 | ih->id) ^ 0xffff; | 1572 | } else { |
1573 | ih = (struct iphdr *)(buf + ih_off); | ||
1574 | ih->tot_len = htons(sh_len + p_len - ih_off); | ||
1575 | ih->id = htons(id); | ||
1576 | ih->check = csum_long(isum_seed + ih->tot_len + | ||
1577 | ih->id) ^ 0xffff; | ||
1578 | } | ||
1566 | 1579 | ||
1567 | /* Update copied tcp header. */ | 1580 | /* Update copied tcp header. */ |
1568 | th = (struct tcphdr *)(buf + th_off); | 1581 | th = (struct tcphdr *)(buf + th_off); |
@@ -1954,6 +1967,7 @@ static void tile_net_setup(struct net_device *dev) | |||
1954 | features |= NETIF_F_HW_CSUM; | 1967 | features |= NETIF_F_HW_CSUM; |
1955 | features |= NETIF_F_SG; | 1968 | features |= NETIF_F_SG; |
1956 | features |= NETIF_F_TSO; | 1969 | features |= NETIF_F_TSO; |
1970 | features |= NETIF_F_TSO6; | ||
1957 | 1971 | ||
1958 | dev->hw_features |= features; | 1972 | dev->hw_features |= features; |
1959 | dev->vlan_features |= features; | 1973 | dev->vlan_features |= features; |