diff options
Diffstat (limited to 'drivers/net/sfc/tx.c')
-rw-r--r-- | drivers/net/sfc/tx.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 389ede43e34a..582fc752da90 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/tcp.h> | 12 | #include <linux/tcp.h> |
13 | #include <linux/ip.h> | 13 | #include <linux/ip.h> |
14 | #include <linux/in.h> | 14 | #include <linux/in.h> |
15 | #include <linux/ipv6.h> | ||
16 | #include <net/ipv6.h> | ||
15 | #include <linux/if_ether.h> | 17 | #include <linux/if_ether.h> |
16 | #include <linux/highmem.h> | 18 | #include <linux/highmem.h> |
17 | #include "net_driver.h" | 19 | #include "net_driver.h" |
@@ -531,6 +533,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) | |||
531 | #define ETH_HDR_LEN(skb) (skb_network_header(skb) - (skb)->data) | 533 | #define ETH_HDR_LEN(skb) (skb_network_header(skb) - (skb)->data) |
532 | #define SKB_TCP_OFF(skb) PTR_DIFF(tcp_hdr(skb), (skb)->data) | 534 | #define SKB_TCP_OFF(skb) PTR_DIFF(tcp_hdr(skb), (skb)->data) |
533 | #define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data) | 535 | #define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data) |
536 | #define SKB_IPV6_OFF(skb) PTR_DIFF(ipv6_hdr(skb), (skb)->data) | ||
534 | 537 | ||
535 | /** | 538 | /** |
536 | * struct tso_state - TSO state for an SKB | 539 | * struct tso_state - TSO state for an SKB |
@@ -543,6 +546,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) | |||
543 | * @unmap_len: Length of SKB fragment | 546 | * @unmap_len: Length of SKB fragment |
544 | * @unmap_addr: DMA address of SKB fragment | 547 | * @unmap_addr: DMA address of SKB fragment |
545 | * @unmap_single: DMA single vs page mapping flag | 548 | * @unmap_single: DMA single vs page mapping flag |
549 | * @protocol: Network protocol (after any VLAN header) | ||
546 | * @header_len: Number of bytes of header | 550 | * @header_len: Number of bytes of header |
547 | * @full_packet_size: Number of bytes to put in each outgoing segment | 551 | * @full_packet_size: Number of bytes to put in each outgoing segment |
548 | * | 552 | * |
@@ -563,6 +567,7 @@ struct tso_state { | |||
563 | dma_addr_t unmap_addr; | 567 | dma_addr_t unmap_addr; |
564 | bool unmap_single; | 568 | bool unmap_single; |
565 | 569 | ||
570 | __be16 protocol; | ||
566 | unsigned header_len; | 571 | unsigned header_len; |
567 | int full_packet_size; | 572 | int full_packet_size; |
568 | }; | 573 | }; |
@@ -570,9 +575,9 @@ struct tso_state { | |||
570 | 575 | ||
571 | /* | 576 | /* |
572 | * Verify that our various assumptions about sk_buffs and the conditions | 577 | * Verify that our various assumptions about sk_buffs and the conditions |
573 | * under which TSO will be attempted hold true. | 578 | * under which TSO will be attempted hold true. Return the protocol number. |
574 | */ | 579 | */ |
575 | static void efx_tso_check_safe(struct sk_buff *skb) | 580 | static __be16 efx_tso_check_protocol(struct sk_buff *skb) |
576 | { | 581 | { |
577 | __be16 protocol = skb->protocol; | 582 | __be16 protocol = skb->protocol; |
578 | 583 | ||
@@ -587,13 +592,22 @@ static void efx_tso_check_safe(struct sk_buff *skb) | |||
587 | if (protocol == htons(ETH_P_IP)) | 592 | if (protocol == htons(ETH_P_IP)) |
588 | skb_set_transport_header(skb, sizeof(*veh) + | 593 | skb_set_transport_header(skb, sizeof(*veh) + |
589 | 4 * ip_hdr(skb)->ihl); | 594 | 4 * ip_hdr(skb)->ihl); |
595 | else if (protocol == htons(ETH_P_IPV6)) | ||
596 | skb_set_transport_header(skb, sizeof(*veh) + | ||
597 | sizeof(struct ipv6hdr)); | ||
590 | } | 598 | } |
591 | 599 | ||
592 | EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IP)); | 600 | if (protocol == htons(ETH_P_IP)) { |
593 | EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); | 601 | EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); |
602 | } else { | ||
603 | EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IPV6)); | ||
604 | EFX_BUG_ON_PARANOID(ipv6_hdr(skb)->nexthdr != NEXTHDR_TCP); | ||
605 | } | ||
594 | EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data) | 606 | EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data) |
595 | + (tcp_hdr(skb)->doff << 2u)) > | 607 | + (tcp_hdr(skb)->doff << 2u)) > |
596 | skb_headlen(skb)); | 608 | skb_headlen(skb)); |
609 | |||
610 | return protocol; | ||
597 | } | 611 | } |
598 | 612 | ||
599 | 613 | ||
@@ -836,7 +850,10 @@ static void tso_start(struct tso_state *st, const struct sk_buff *skb) | |||
836 | + PTR_DIFF(tcp_hdr(skb), skb->data)); | 850 | + PTR_DIFF(tcp_hdr(skb), skb->data)); |
837 | st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size; | 851 | st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size; |
838 | 852 | ||
839 | st->ipv4_id = ntohs(ip_hdr(skb)->id); | 853 | if (st->protocol == htons(ETH_P_IP)) |
854 | st->ipv4_id = ntohs(ip_hdr(skb)->id); | ||
855 | else | ||
856 | st->ipv4_id = 0; | ||
840 | st->seqnum = ntohl(tcp_hdr(skb)->seq); | 857 | st->seqnum = ntohl(tcp_hdr(skb)->seq); |
841 | 858 | ||
842 | EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg); | 859 | EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg); |
@@ -951,7 +968,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, | |||
951 | struct tso_state *st) | 968 | struct tso_state *st) |
952 | { | 969 | { |
953 | struct efx_tso_header *tsoh; | 970 | struct efx_tso_header *tsoh; |
954 | struct iphdr *tsoh_iph; | ||
955 | struct tcphdr *tsoh_th; | 971 | struct tcphdr *tsoh_th; |
956 | unsigned ip_length; | 972 | unsigned ip_length; |
957 | u8 *header; | 973 | u8 *header; |
@@ -975,7 +991,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, | |||
975 | 991 | ||
976 | header = TSOH_BUFFER(tsoh); | 992 | header = TSOH_BUFFER(tsoh); |
977 | tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb)); | 993 | tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb)); |
978 | tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb)); | ||
979 | 994 | ||
980 | /* Copy and update the headers. */ | 995 | /* Copy and update the headers. */ |
981 | memcpy(header, skb->data, st->header_len); | 996 | memcpy(header, skb->data, st->header_len); |
@@ -993,11 +1008,22 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, | |||
993 | tsoh_th->fin = tcp_hdr(skb)->fin; | 1008 | tsoh_th->fin = tcp_hdr(skb)->fin; |
994 | tsoh_th->psh = tcp_hdr(skb)->psh; | 1009 | tsoh_th->psh = tcp_hdr(skb)->psh; |
995 | } | 1010 | } |
996 | tsoh_iph->tot_len = htons(ip_length); | ||
997 | 1011 | ||
998 | /* Linux leaves suitable gaps in the IP ID space for us to fill. */ | 1012 | if (st->protocol == htons(ETH_P_IP)) { |
999 | tsoh_iph->id = htons(st->ipv4_id); | 1013 | struct iphdr *tsoh_iph = |
1000 | st->ipv4_id++; | 1014 | (struct iphdr *)(header + SKB_IPV4_OFF(skb)); |
1015 | |||
1016 | tsoh_iph->tot_len = htons(ip_length); | ||
1017 | |||
1018 | /* Linux leaves suitable gaps in the IP ID space for us to fill. */ | ||
1019 | tsoh_iph->id = htons(st->ipv4_id); | ||
1020 | st->ipv4_id++; | ||
1021 | } else { | ||
1022 | struct ipv6hdr *tsoh_iph = | ||
1023 | (struct ipv6hdr *)(header + SKB_IPV6_OFF(skb)); | ||
1024 | |||
1025 | tsoh_iph->payload_len = htons(ip_length - sizeof(*tsoh_iph)); | ||
1026 | } | ||
1001 | 1027 | ||
1002 | st->packet_space = skb_shinfo(skb)->gso_size; | 1028 | st->packet_space = skb_shinfo(skb)->gso_size; |
1003 | ++tx_queue->tso_packets; | 1029 | ++tx_queue->tso_packets; |
@@ -1027,8 +1053,8 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, | |||
1027 | int frag_i, rc, rc2 = NETDEV_TX_OK; | 1053 | int frag_i, rc, rc2 = NETDEV_TX_OK; |
1028 | struct tso_state state; | 1054 | struct tso_state state; |
1029 | 1055 | ||
1030 | /* Verify TSO is safe - these checks should never fail. */ | 1056 | /* Find the packet protocol and sanity-check it */ |
1031 | efx_tso_check_safe(skb); | 1057 | state.protocol = efx_tso_check_protocol(skb); |
1032 | 1058 | ||
1033 | EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); | 1059 | EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); |
1034 | 1060 | ||