]>
Commit | Line | Data |
---|---|---|
a7b0967d MT |
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 | |
5 | ||
6 | Enable send side checksum offload. | |
7 | ||
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> | |
11 | --- | |
12 | drivers/net/hyperv/hyperv_net.h | 10 ++++++ | |
13 | drivers/net/hyperv/netvsc_drv.c | 69 +++++++++++++++++++++++++++++++++++++++-- | |
14 | 2 files changed, 77 insertions(+), 2 deletions(-) | |
15 | ||
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 | |
23 | ||
24 | +#define INFO_IPV4 2 | |
25 | +#define INFO_IPV6 4 | |
26 | +#define INFO_TCP 2 | |
27 | +#define INFO_UDP 4 | |
28 | + | |
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) | |
34 | ||
35 | ||
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; | |
43 | } | |
44 | ||
45 | +static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off) | |
46 | +{ | |
47 | + u32 ret_val = TRANSPORT_INFO_NOT_IP; | |
48 | + | |
49 | + if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) && | |
50 | + (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) { | |
51 | + goto not_ip; | |
52 | + } | |
53 | + | |
54 | + *trans_off = skb_transport_offset(skb); | |
55 | + | |
56 | + if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) { | |
57 | + struct iphdr *iphdr = ip_hdr(skb); | |
58 | + | |
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; | |
63 | + } else { | |
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; | |
68 | + } | |
69 | + | |
70 | +not_ip: | |
71 | + return ret_val; | |
72 | +} | |
73 | + | |
74 | static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |
75 | { | |
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) | |
78 | u32 rndis_msg_size; | |
79 | bool isvlan; | |
80 | struct rndis_per_packet_info *ppi; | |
81 | + struct ndis_tcp_ip_checksum_info *csum_info; | |
82 | + int hdr_offset; | |
83 | + u32 net_trans_info; | |
84 | + | |
85 | ||
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) | |
89 | VLAN_PRIO_SHIFT; | |
90 | } | |
91 | ||
92 | + net_trans_info = get_net_transport_info(skb, &hdr_offset); | |
93 | + if (net_trans_info == TRANSPORT_INFO_NOT_IP) | |
94 | + goto do_send; | |
95 | + | |
96 | + /* | |
97 | + * Setup the sendside checksum offload only if this is not a | |
98 | + * GSO packet. | |
99 | + */ | |
100 | + if (skb_is_gso(skb)) | |
101 | + goto do_send; | |
102 | + | |
103 | + rndis_msg_size += NDIS_CSUM_PPI_SIZE; | |
104 | + ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, | |
105 | + TCPIP_CHKSUM_PKTINFO); | |
106 | + | |
107 | + csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi + | |
108 | + ppi->ppi_offset); | |
109 | + | |
110 | + if (net_trans_info & (INFO_IPV4 << 16)) | |
111 | + csum_info->transmit.is_ipv4 = 1; | |
112 | + else | |
113 | + csum_info->transmit.is_ipv6 = 1; | |
114 | + | |
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; | |
120 | + } | |
121 | + | |
122 | +do_send: | |
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; | |
128 | ||
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 | | |
134 | + NETIF_F_IP_CSUM; | |
135 | ||
136 | SET_ETHTOOL_OPS(net, ðtool_ops); | |
137 | SET_NETDEV_DEV(net, &dev->device); | |
138 | -- | |
139 | 2.4.3 | |
140 |