diff options
| author | KY Srinivasan <kys@microsoft.com> | 2014-03-08 22:23:18 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-03-10 15:51:37 -0400 |
| commit | 77bf5487946254798ed7f265877939c703189f1e (patch) | |
| tree | 5420a2dc396c09173940c73d761f0aea0fd6bed5 | |
| parent | 08cd04bf6d5b14ea90845b596d371bfa33eaba06 (diff) | |
Drivers: net: hyperv: Enable large send offload
Enable segmentation offload.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 40 | ||||
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 38 |
2 files changed, 74 insertions, 4 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 4cf238234321..7d06b4959383 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
| @@ -742,6 +742,10 @@ struct ndis_oject_header { | |||
| 742 | #define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 | 742 | #define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 |
| 743 | #define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 | 743 | #define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 |
| 744 | 744 | ||
| 745 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE 1 | ||
| 746 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0 | ||
| 747 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1 | ||
| 748 | |||
| 745 | /* | 749 | /* |
| 746 | * New offload OIDs for NDIS 6 | 750 | * New offload OIDs for NDIS 6 |
| 747 | */ | 751 | */ |
| @@ -804,12 +808,48 @@ struct ndis_tcp_ip_checksum_info { | |||
| 804 | }; | 808 | }; |
| 805 | }; | 809 | }; |
| 806 | 810 | ||
| 811 | struct ndis_tcp_lso_info { | ||
| 812 | union { | ||
| 813 | struct { | ||
| 814 | u32 unused:30; | ||
| 815 | u32 type:1; | ||
| 816 | u32 reserved2:1; | ||
| 817 | } transmit; | ||
| 818 | struct { | ||
| 819 | u32 mss:20; | ||
| 820 | u32 tcp_header_offset:10; | ||
| 821 | u32 type:1; | ||
| 822 | u32 reserved2:1; | ||
| 823 | } lso_v1_transmit; | ||
| 824 | struct { | ||
| 825 | u32 tcp_payload:30; | ||
| 826 | u32 type:1; | ||
| 827 | u32 reserved2:1; | ||
| 828 | } lso_v1_transmit_complete; | ||
| 829 | struct { | ||
| 830 | u32 mss:20; | ||
| 831 | u32 tcp_header_offset:10; | ||
| 832 | u32 type:1; | ||
| 833 | u32 ip_version:1; | ||
| 834 | } lso_v2_transmit; | ||
| 835 | struct { | ||
| 836 | u32 reserved:30; | ||
| 837 | u32 type:1; | ||
| 838 | u32 reserved2:1; | ||
| 839 | } lso_v2_transmit_complete; | ||
| 840 | u32 value; | ||
| 841 | }; | ||
| 842 | }; | ||
| 843 | |||
| 807 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | 844 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ |
| 808 | sizeof(struct ndis_pkt_8021q_info)) | 845 | sizeof(struct ndis_pkt_8021q_info)) |
| 809 | 846 | ||
| 810 | #define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | 847 | #define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ |
| 811 | sizeof(struct ndis_tcp_ip_checksum_info)) | 848 | sizeof(struct ndis_tcp_ip_checksum_info)) |
| 812 | 849 | ||
| 850 | #define NDIS_LSO_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | ||
| 851 | sizeof(struct ndis_tcp_lso_info)) | ||
| 852 | |||
| 813 | /* Format of Information buffer passed in a SetRequest for the OID */ | 853 | /* Format of Information buffer passed in a SetRequest for the OID */ |
| 814 | /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ | 854 | /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ |
| 815 | struct rndis_config_parameter_info { | 855 | struct rndis_config_parameter_info { |
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 697837537ccb..3d069901e6d9 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
| @@ -298,6 +298,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
| 298 | bool isvlan; | 298 | bool isvlan; |
| 299 | struct rndis_per_packet_info *ppi; | 299 | struct rndis_per_packet_info *ppi; |
| 300 | struct ndis_tcp_ip_checksum_info *csum_info; | 300 | struct ndis_tcp_ip_checksum_info *csum_info; |
| 301 | struct ndis_tcp_lso_info *lso_info; | ||
| 301 | int hdr_offset; | 302 | int hdr_offset; |
| 302 | u32 net_trans_info; | 303 | u32 net_trans_info; |
| 303 | 304 | ||
| @@ -377,7 +378,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
| 377 | * GSO packet. | 378 | * GSO packet. |
| 378 | */ | 379 | */ |
| 379 | if (skb_is_gso(skb)) | 380 | if (skb_is_gso(skb)) |
| 380 | goto do_send; | 381 | goto do_lso; |
| 381 | 382 | ||
| 382 | rndis_msg_size += NDIS_CSUM_PPI_SIZE; | 383 | rndis_msg_size += NDIS_CSUM_PPI_SIZE; |
| 383 | ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, | 384 | ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, |
| @@ -397,6 +398,35 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
| 397 | } else if (net_trans_info & INFO_UDP) { | 398 | } else if (net_trans_info & INFO_UDP) { |
| 398 | csum_info->transmit.udp_checksum = 1; | 399 | csum_info->transmit.udp_checksum = 1; |
| 399 | } | 400 | } |
| 401 | goto do_send; | ||
| 402 | |||
| 403 | do_lso: | ||
| 404 | rndis_msg_size += NDIS_LSO_PPI_SIZE; | ||
| 405 | ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE, | ||
| 406 | TCP_LARGESEND_PKTINFO); | ||
| 407 | |||
| 408 | lso_info = (struct ndis_tcp_lso_info *)((void *)ppi + | ||
| 409 | ppi->ppi_offset); | ||
| 410 | |||
| 411 | lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; | ||
| 412 | if (net_trans_info & (INFO_IPV4 << 16)) { | ||
| 413 | lso_info->lso_v2_transmit.ip_version = | ||
| 414 | NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4; | ||
| 415 | ip_hdr(skb)->tot_len = 0; | ||
| 416 | ip_hdr(skb)->check = 0; | ||
| 417 | tcp_hdr(skb)->check = | ||
| 418 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
| 419 | ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); | ||
| 420 | } else { | ||
| 421 | lso_info->lso_v2_transmit.ip_version = | ||
| 422 | NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6; | ||
| 423 | ipv6_hdr(skb)->payload_len = 0; | ||
| 424 | tcp_hdr(skb)->check = | ||
| 425 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
| 426 | &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); | ||
| 427 | } | ||
| 428 | lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset; | ||
| 429 | lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size; | ||
| 400 | 430 | ||
| 401 | do_send: | 431 | do_send: |
| 402 | /* Start filling in the page buffers with the rndis hdr */ | 432 | /* Start filling in the page buffers with the rndis hdr */ |
| @@ -652,10 +682,10 @@ static int netvsc_probe(struct hv_device *dev, | |||
| 652 | 682 | ||
| 653 | net->netdev_ops = &device_ops; | 683 | net->netdev_ops = &device_ops; |
| 654 | 684 | ||
| 655 | /* TODO: Add GSO and Checksum offload */ | 685 | net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM | |
| 656 | net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM; | 686 | NETIF_F_TSO; |
| 657 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | | 687 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | |
| 658 | NETIF_F_IP_CSUM; | 688 | NETIF_F_IP_CSUM | NETIF_F_TSO; |
| 659 | 689 | ||
| 660 | SET_ETHTOOL_OPS(net, ðtool_ops); | 690 | SET_ETHTOOL_OPS(net, ðtool_ops); |
| 661 | SET_NETDEV_DEV(net, &dev->device); | 691 | SET_NETDEV_DEV(net, &dev->device); |
