aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKY Srinivasan <kys@microsoft.com>2014-03-08 22:23:18 -0500
committerDavid S. Miller <davem@davemloft.net>2014-03-10 15:51:37 -0400
commit77bf5487946254798ed7f265877939c703189f1e (patch)
tree5420a2dc396c09173940c73d761f0aea0fd6bed5
parent08cd04bf6d5b14ea90845b596d371bfa33eaba06 (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.h40
-rw-r--r--drivers/net/hyperv/netvsc_drv.c38
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
811struct 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. */
815struct rndis_config_parameter_info { 855struct 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
403do_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
401do_send: 431do_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, &ethtool_ops); 690 SET_ETHTOOL_OPS(net, &ethtool_ops);
661 SET_NETDEV_DEV(net, &dev->device); 691 SET_NETDEV_DEV(net, &dev->device);