1 From d2a0be7f4263eb669af84240c5424a72cce4cdb4 Mon Sep 17 00:00:00 2001
2 From: KY Srinivasan <kys@microsoft.com>
3 Date: Sat, 8 Mar 2014 19:23:17 -0800
4 Subject: [PATCH 09/25] Drivers: net: hyperv: Enable send side checksum offload
6 Enable send side checksum offload.
8 Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
9 Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
10 Signed-off-by: David S. Miller <davem@davemloft.net>
12 drivers/net/hyperv/hyperv_net.h | 10 ++++++
13 drivers/net/hyperv/netvsc_drv.c | 69 +++++++++++++++++++++++++++++++++++++++--
14 2 files changed, 77 insertions(+), 2 deletions(-)
16 diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
17 index faeb74623fbd..4cf238234321 100644
18 --- a/drivers/net/hyperv/hyperv_net.h
19 +++ b/drivers/net/hyperv/hyperv_net.h
20 @@ -1035,6 +1035,16 @@ struct rndis_message {
21 #define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
22 #define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
29 +#define TRANSPORT_INFO_NOT_IP 0
30 +#define TRANSPORT_INFO_IPV4_TCP ((INFO_IPV4 << 16) | INFO_TCP)
31 +#define TRANSPORT_INFO_IPV4_UDP ((INFO_IPV4 << 16) | INFO_UDP)
32 +#define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP)
33 +#define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP)
36 #endif /* _HYPERV_NET_H */
37 diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
38 index 7438360b7a02..2fab69ac61ef 100644
39 --- a/drivers/net/hyperv/netvsc_drv.c
40 +++ b/drivers/net/hyperv/netvsc_drv.c
41 @@ -257,6 +257,35 @@ static int netvsc_get_slots(struct sk_buff *skb)
42 return slots + frag_slots;
45 +static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off)
47 + u32 ret_val = TRANSPORT_INFO_NOT_IP;
49 + if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) &&
50 + (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) {
54 + *trans_off = skb_transport_offset(skb);
56 + if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) {
57 + struct iphdr *iphdr = ip_hdr(skb);
59 + if (iphdr->protocol == IPPROTO_TCP)
60 + ret_val = TRANSPORT_INFO_IPV4_TCP;
61 + else if (iphdr->protocol == IPPROTO_UDP)
62 + ret_val = TRANSPORT_INFO_IPV4_UDP;
64 + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
65 + ret_val = TRANSPORT_INFO_IPV6_TCP;
66 + else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
67 + ret_val = TRANSPORT_INFO_IPV6_UDP;
74 static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
76 struct net_device_context *net_device_ctx = netdev_priv(net);
77 @@ -269,6 +298,10 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
80 struct rndis_per_packet_info *ppi;
81 + struct ndis_tcp_ip_checksum_info *csum_info;
86 /* We will atmost need two pages to describe the rndis
87 * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
88 @@ -336,6 +369,37 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
92 + net_trans_info = get_net_transport_info(skb, &hdr_offset);
93 + if (net_trans_info == TRANSPORT_INFO_NOT_IP)
97 + * Setup the sendside checksum offload only if this is not a
100 + if (skb_is_gso(skb))
103 + rndis_msg_size += NDIS_CSUM_PPI_SIZE;
104 + ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
105 + TCPIP_CHKSUM_PKTINFO);
107 + csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
110 + if (net_trans_info & (INFO_IPV4 << 16))
111 + csum_info->transmit.is_ipv4 = 1;
113 + csum_info->transmit.is_ipv6 = 1;
115 + if (net_trans_info & INFO_TCP) {
116 + csum_info->transmit.tcp_checksum = 1;
117 + csum_info->transmit.tcp_header_offset = hdr_offset;
118 + } else if (net_trans_info & INFO_UDP) {
119 + csum_info->transmit.udp_checksum = 1;
123 /* Start filling in the page buffers with the rndis hdr */
124 rndis_msg->msg_len += rndis_msg_size;
125 packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
126 @@ -592,8 +656,9 @@ static int netvsc_probe(struct hv_device *dev,
127 net->netdev_ops = &device_ops;
129 /* TODO: Add GSO and Checksum offload */
130 - net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG;
131 - net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM;
132 + net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM;
133 + net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM |
136 SET_ETHTOOL_OPS(net, ðtool_ops);
137 SET_NETDEV_DEV(net, &dev->device);