diff options
author | KY Srinivasan <kys@microsoft.com> | 2014-03-08 22:23:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-10 15:51:37 -0400 |
commit | 08cd04bf6d5b14ea90845b596d371bfa33eaba06 (patch) | |
tree | b6b49bf2a1deb8aff42e560e733035be2c550c5b | |
parent | e3d605ed441cf4d113f9a1cf9e1b3f7cabe0d781 (diff) |
Drivers: net: hyperv: Enable send side checksum offload
Enable send 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>
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 10 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 69 |
2 files changed, 77 insertions, 2 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index faeb74623fbd..4cf238234321 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
@@ -1035,6 +1035,16 @@ struct rndis_message { | |||
1035 | #define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 | 1035 | #define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 |
1036 | #define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 | 1036 | #define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 |
1037 | 1037 | ||
1038 | #define INFO_IPV4 2 | ||
1039 | #define INFO_IPV6 4 | ||
1040 | #define INFO_TCP 2 | ||
1041 | #define INFO_UDP 4 | ||
1042 | |||
1043 | #define TRANSPORT_INFO_NOT_IP 0 | ||
1044 | #define TRANSPORT_INFO_IPV4_TCP ((INFO_IPV4 << 16) | INFO_TCP) | ||
1045 | #define TRANSPORT_INFO_IPV4_UDP ((INFO_IPV4 << 16) | INFO_UDP) | ||
1046 | #define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP) | ||
1047 | #define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP) | ||
1038 | 1048 | ||
1039 | 1049 | ||
1040 | #endif /* _HYPERV_NET_H */ | 1050 | #endif /* _HYPERV_NET_H */ |
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 9bee0650c7ca..697837537ccb 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -257,6 +257,35 @@ static int netvsc_get_slots(struct sk_buff *skb) | |||
257 | return slots + frag_slots; | 257 | return slots + frag_slots; |
258 | } | 258 | } |
259 | 259 | ||
260 | static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off) | ||
261 | { | ||
262 | u32 ret_val = TRANSPORT_INFO_NOT_IP; | ||
263 | |||
264 | if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) && | ||
265 | (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) { | ||
266 | goto not_ip; | ||
267 | } | ||
268 | |||
269 | *trans_off = skb_transport_offset(skb); | ||
270 | |||
271 | if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) { | ||
272 | struct iphdr *iphdr = ip_hdr(skb); | ||
273 | |||
274 | if (iphdr->protocol == IPPROTO_TCP) | ||
275 | ret_val = TRANSPORT_INFO_IPV4_TCP; | ||
276 | else if (iphdr->protocol == IPPROTO_UDP) | ||
277 | ret_val = TRANSPORT_INFO_IPV4_UDP; | ||
278 | } else { | ||
279 | if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) | ||
280 | ret_val = TRANSPORT_INFO_IPV6_TCP; | ||
281 | else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) | ||
282 | ret_val = TRANSPORT_INFO_IPV6_UDP; | ||
283 | } | ||
284 | |||
285 | not_ip: | ||
286 | return ret_val; | ||
287 | } | ||
288 | |||
260 | static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | 289 | static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) |
261 | { | 290 | { |
262 | struct net_device_context *net_device_ctx = netdev_priv(net); | 291 | struct net_device_context *net_device_ctx = netdev_priv(net); |
@@ -268,6 +297,10 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
268 | u32 rndis_msg_size; | 297 | u32 rndis_msg_size; |
269 | bool isvlan; | 298 | bool isvlan; |
270 | struct rndis_per_packet_info *ppi; | 299 | struct rndis_per_packet_info *ppi; |
300 | struct ndis_tcp_ip_checksum_info *csum_info; | ||
301 | int hdr_offset; | ||
302 | u32 net_trans_info; | ||
303 | |||
271 | 304 | ||
272 | /* We will atmost need two pages to describe the rndis | 305 | /* We will atmost need two pages to describe the rndis |
273 | * header. We can only transmit MAX_PAGE_BUFFER_COUNT number | 306 | * header. We can only transmit MAX_PAGE_BUFFER_COUNT number |
@@ -335,6 +368,37 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
335 | VLAN_PRIO_SHIFT; | 368 | VLAN_PRIO_SHIFT; |
336 | } | 369 | } |
337 | 370 | ||
371 | net_trans_info = get_net_transport_info(skb, &hdr_offset); | ||
372 | if (net_trans_info == TRANSPORT_INFO_NOT_IP) | ||
373 | goto do_send; | ||
374 | |||
375 | /* | ||
376 | * Setup the sendside checksum offload only if this is not a | ||
377 | * GSO packet. | ||
378 | */ | ||
379 | if (skb_is_gso(skb)) | ||
380 | goto do_send; | ||
381 | |||
382 | rndis_msg_size += NDIS_CSUM_PPI_SIZE; | ||
383 | ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, | ||
384 | TCPIP_CHKSUM_PKTINFO); | ||
385 | |||
386 | csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi + | ||
387 | ppi->ppi_offset); | ||
388 | |||
389 | if (net_trans_info & (INFO_IPV4 << 16)) | ||
390 | csum_info->transmit.is_ipv4 = 1; | ||
391 | else | ||
392 | csum_info->transmit.is_ipv6 = 1; | ||
393 | |||
394 | if (net_trans_info & INFO_TCP) { | ||
395 | csum_info->transmit.tcp_checksum = 1; | ||
396 | csum_info->transmit.tcp_header_offset = hdr_offset; | ||
397 | } else if (net_trans_info & INFO_UDP) { | ||
398 | csum_info->transmit.udp_checksum = 1; | ||
399 | } | ||
400 | |||
401 | do_send: | ||
338 | /* Start filling in the page buffers with the rndis hdr */ | 402 | /* Start filling in the page buffers with the rndis hdr */ |
339 | rndis_msg->msg_len += rndis_msg_size; | 403 | rndis_msg->msg_len += rndis_msg_size; |
340 | packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, | 404 | packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, |
@@ -589,8 +653,9 @@ static int netvsc_probe(struct hv_device *dev, | |||
589 | net->netdev_ops = &device_ops; | 653 | net->netdev_ops = &device_ops; |
590 | 654 | ||
591 | /* TODO: Add GSO and Checksum offload */ | 655 | /* TODO: Add GSO and Checksum offload */ |
592 | net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG; | 656 | net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM; |
593 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM; | 657 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | |
658 | NETIF_F_IP_CSUM; | ||
594 | 659 | ||
595 | SET_ETHTOOL_OPS(net, ðtool_ops); | 660 | SET_ETHTOOL_OPS(net, ðtool_ops); |
596 | SET_NETDEV_DEV(net, &dev->device); | 661 | SET_NETDEV_DEV(net, &dev->device); |