diff options
| author | KY Srinivasan <kys@microsoft.com> | 2014-03-08 22:23:16 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-03-10 15:51:37 -0400 |
| commit | e3d605ed441cf4d113f9a1cf9e1b3f7cabe0d781 (patch) | |
| tree | e339f94436e35b9b68eb84ba9fe80f3315206563 /drivers/net/hyperv | |
| parent | 4a0e70ae5e3858052f6d91564bf3484f1eb91dc7 (diff) | |
Drivers: net: hyperv: Enable receive side IP checksum offload
Enable receive side checksum 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>
Diffstat (limited to 'drivers/net/hyperv')
| -rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 33 | ||||
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 19 | ||||
| -rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 4 |
3 files changed, 50 insertions, 6 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 8bc4e766589b..faeb74623fbd 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | 30 | ||
| 31 | /* Fwd declaration */ | 31 | /* Fwd declaration */ |
| 32 | struct hv_netvsc_packet; | 32 | struct hv_netvsc_packet; |
| 33 | struct ndis_tcp_ip_checksum_info; | ||
| 33 | 34 | ||
| 34 | /* Represent the xfer page packet which contains 1 or more netvsc packet */ | 35 | /* Represent the xfer page packet which contains 1 or more netvsc packet */ |
| 35 | struct xferpage_packet { | 36 | struct xferpage_packet { |
| @@ -117,7 +118,8 @@ int netvsc_send(struct hv_device *device, | |||
| 117 | void netvsc_linkstatus_callback(struct hv_device *device_obj, | 118 | void netvsc_linkstatus_callback(struct hv_device *device_obj, |
| 118 | unsigned int status); | 119 | unsigned int status); |
| 119 | int netvsc_recv_callback(struct hv_device *device_obj, | 120 | int netvsc_recv_callback(struct hv_device *device_obj, |
| 120 | struct hv_netvsc_packet *packet); | 121 | struct hv_netvsc_packet *packet, |
| 122 | struct ndis_tcp_ip_checksum_info *csum_info); | ||
| 121 | int rndis_filter_open(struct hv_device *dev); | 123 | int rndis_filter_open(struct hv_device *dev); |
| 122 | int rndis_filter_close(struct hv_device *dev); | 124 | int rndis_filter_close(struct hv_device *dev); |
| 123 | int rndis_filter_device_add(struct hv_device *dev, | 125 | int rndis_filter_device_add(struct hv_device *dev, |
| @@ -776,9 +778,38 @@ struct ndis_offload_params { | |||
| 776 | }; | 778 | }; |
| 777 | }; | 779 | }; |
| 778 | 780 | ||
| 781 | struct ndis_tcp_ip_checksum_info { | ||
| 782 | union { | ||
| 783 | struct { | ||
| 784 | u32 is_ipv4:1; | ||
| 785 | u32 is_ipv6:1; | ||
| 786 | u32 tcp_checksum:1; | ||
| 787 | u32 udp_checksum:1; | ||
| 788 | u32 ip_header_checksum:1; | ||
| 789 | u32 reserved:11; | ||
| 790 | u32 tcp_header_offset:10; | ||
| 791 | } transmit; | ||
| 792 | struct { | ||
| 793 | u32 tcp_checksum_failed:1; | ||
| 794 | u32 udp_checksum_failed:1; | ||
| 795 | u32 ip_checksum_failed:1; | ||
| 796 | u32 tcp_checksum_succeeded:1; | ||
| 797 | u32 udp_checksum_succeeded:1; | ||
| 798 | u32 ip_checksum_succeeded:1; | ||
| 799 | u32 loopback:1; | ||
| 800 | u32 tcp_checksum_value_invalid:1; | ||
| 801 | u32 ip_checksum_value_invalid:1; | ||
| 802 | } receive; | ||
| 803 | u32 value; | ||
| 804 | }; | ||
| 805 | }; | ||
| 806 | |||
| 779 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | 807 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ |
| 780 | sizeof(struct ndis_pkt_8021q_info)) | 808 | sizeof(struct ndis_pkt_8021q_info)) |
| 781 | 809 | ||
| 810 | #define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | ||
| 811 | sizeof(struct ndis_tcp_ip_checksum_info)) | ||
| 812 | |||
| 782 | /* Format of Information buffer passed in a SetRequest for the OID */ | 813 | /* Format of Information buffer passed in a SetRequest for the OID */ |
| 783 | /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ | 814 | /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ |
| 784 | struct rndis_config_parameter_info { | 815 | struct rndis_config_parameter_info { |
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 7010c0630d24..9bee0650c7ca 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
| @@ -391,7 +391,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, | |||
| 391 | * "wire" on the specified device. | 391 | * "wire" on the specified device. |
| 392 | */ | 392 | */ |
| 393 | int netvsc_recv_callback(struct hv_device *device_obj, | 393 | int netvsc_recv_callback(struct hv_device *device_obj, |
| 394 | struct hv_netvsc_packet *packet) | 394 | struct hv_netvsc_packet *packet, |
| 395 | struct ndis_tcp_ip_checksum_info *csum_info) | ||
| 395 | { | 396 | { |
| 396 | struct net_device *net; | 397 | struct net_device *net; |
| 397 | struct sk_buff *skb; | 398 | struct sk_buff *skb; |
| @@ -418,7 +419,17 @@ int netvsc_recv_callback(struct hv_device *device_obj, | |||
| 418 | packet->total_data_buflen); | 419 | packet->total_data_buflen); |
| 419 | 420 | ||
| 420 | skb->protocol = eth_type_trans(skb, net); | 421 | skb->protocol = eth_type_trans(skb, net); |
| 421 | skb->ip_summed = CHECKSUM_NONE; | 422 | if (csum_info) { |
| 423 | /* We only look at the IP checksum here. | ||
| 424 | * Should we be dropping the packet if checksum | ||
| 425 | * failed? How do we deal with other checksums - TCP/UDP? | ||
| 426 | */ | ||
| 427 | if (csum_info->receive.ip_checksum_succeeded) | ||
| 428 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 429 | else | ||
| 430 | skb->ip_summed = CHECKSUM_NONE; | ||
| 431 | } | ||
| 432 | |||
| 422 | if (packet->vlan_tci & VLAN_TAG_PRESENT) | 433 | if (packet->vlan_tci & VLAN_TAG_PRESENT) |
| 423 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), | 434 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), |
| 424 | packet->vlan_tci); | 435 | packet->vlan_tci); |
| @@ -578,8 +589,8 @@ static int netvsc_probe(struct hv_device *dev, | |||
| 578 | net->netdev_ops = &device_ops; | 589 | net->netdev_ops = &device_ops; |
| 579 | 590 | ||
| 580 | /* TODO: Add GSO and Checksum offload */ | 591 | /* TODO: Add GSO and Checksum offload */ |
| 581 | net->hw_features = NETIF_F_SG; | 592 | net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG; |
| 582 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG; | 593 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM; |
| 583 | 594 | ||
| 584 | SET_ETHTOOL_OPS(net, ðtool_ops); | 595 | SET_ETHTOOL_OPS(net, ðtool_ops); |
| 585 | SET_NETDEV_DEV(net, &dev->device); | 596 | SET_NETDEV_DEV(net, &dev->device); |
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 42bfb3a11efd..54553df74cd2 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
| @@ -350,6 +350,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev, | |||
| 350 | struct rndis_packet *rndis_pkt; | 350 | struct rndis_packet *rndis_pkt; |
| 351 | u32 data_offset; | 351 | u32 data_offset; |
| 352 | struct ndis_pkt_8021q_info *vlan; | 352 | struct ndis_pkt_8021q_info *vlan; |
| 353 | struct ndis_tcp_ip_checksum_info *csum_info; | ||
| 353 | 354 | ||
| 354 | rndis_pkt = &msg->msg.pkt; | 355 | rndis_pkt = &msg->msg.pkt; |
| 355 | 356 | ||
| @@ -388,7 +389,8 @@ static void rndis_filter_receive_data(struct rndis_device *dev, | |||
| 388 | pkt->vlan_tci = 0; | 389 | pkt->vlan_tci = 0; |
| 389 | } | 390 | } |
| 390 | 391 | ||
| 391 | netvsc_recv_callback(dev->net_dev->dev, pkt); | 392 | csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO); |
| 393 | netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info); | ||
| 392 | } | 394 | } |
| 393 | 395 | ||
| 394 | int rndis_filter_receive(struct hv_device *dev, | 396 | int rndis_filter_receive(struct hv_device *dev, |
