diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 337 |
1 files changed, 285 insertions, 52 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index d6fce9750b95..4e4cf9e0c8d7 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -128,6 +128,27 @@ static int netvsc_close(struct net_device *net) | |||
128 | return ret; | 128 | return ret; |
129 | } | 129 | } |
130 | 130 | ||
131 | static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size, | ||
132 | int pkt_type) | ||
133 | { | ||
134 | struct rndis_packet *rndis_pkt; | ||
135 | struct rndis_per_packet_info *ppi; | ||
136 | |||
137 | rndis_pkt = &msg->msg.pkt; | ||
138 | rndis_pkt->data_offset += ppi_size; | ||
139 | |||
140 | ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt + | ||
141 | rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len); | ||
142 | |||
143 | ppi->size = ppi_size; | ||
144 | ppi->type = pkt_type; | ||
145 | ppi->ppi_offset = sizeof(struct rndis_per_packet_info); | ||
146 | |||
147 | rndis_pkt->per_pkt_info_len += ppi_size; | ||
148 | |||
149 | return ppi; | ||
150 | } | ||
151 | |||
131 | static void netvsc_xmit_completion(void *context) | 152 | static void netvsc_xmit_completion(void *context) |
132 | { | 153 | { |
133 | struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; | 154 | struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; |
@@ -140,22 +161,164 @@ static void netvsc_xmit_completion(void *context) | |||
140 | dev_kfree_skb_any(skb); | 161 | dev_kfree_skb_any(skb); |
141 | } | 162 | } |
142 | 163 | ||
164 | static u32 fill_pg_buf(struct page *page, u32 offset, u32 len, | ||
165 | struct hv_page_buffer *pb) | ||
166 | { | ||
167 | int j = 0; | ||
168 | |||
169 | /* Deal with compund pages by ignoring unused part | ||
170 | * of the page. | ||
171 | */ | ||
172 | page += (offset >> PAGE_SHIFT); | ||
173 | offset &= ~PAGE_MASK; | ||
174 | |||
175 | while (len > 0) { | ||
176 | unsigned long bytes; | ||
177 | |||
178 | bytes = PAGE_SIZE - offset; | ||
179 | if (bytes > len) | ||
180 | bytes = len; | ||
181 | pb[j].pfn = page_to_pfn(page); | ||
182 | pb[j].offset = offset; | ||
183 | pb[j].len = bytes; | ||
184 | |||
185 | offset += bytes; | ||
186 | len -= bytes; | ||
187 | |||
188 | if (offset == PAGE_SIZE && len) { | ||
189 | page++; | ||
190 | offset = 0; | ||
191 | j++; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | return j + 1; | ||
196 | } | ||
197 | |||
198 | static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, | ||
199 | struct hv_page_buffer *pb) | ||
200 | { | ||
201 | u32 slots_used = 0; | ||
202 | char *data = skb->data; | ||
203 | int frags = skb_shinfo(skb)->nr_frags; | ||
204 | int i; | ||
205 | |||
206 | /* The packet is laid out thus: | ||
207 | * 1. hdr | ||
208 | * 2. skb linear data | ||
209 | * 3. skb fragment data | ||
210 | */ | ||
211 | if (hdr != NULL) | ||
212 | slots_used += fill_pg_buf(virt_to_page(hdr), | ||
213 | offset_in_page(hdr), | ||
214 | len, &pb[slots_used]); | ||
215 | |||
216 | slots_used += fill_pg_buf(virt_to_page(data), | ||
217 | offset_in_page(data), | ||
218 | skb_headlen(skb), &pb[slots_used]); | ||
219 | |||
220 | for (i = 0; i < frags; i++) { | ||
221 | skb_frag_t *frag = skb_shinfo(skb)->frags + i; | ||
222 | |||
223 | slots_used += fill_pg_buf(skb_frag_page(frag), | ||
224 | frag->page_offset, | ||
225 | skb_frag_size(frag), &pb[slots_used]); | ||
226 | } | ||
227 | return slots_used; | ||
228 | } | ||
229 | |||
230 | static int count_skb_frag_slots(struct sk_buff *skb) | ||
231 | { | ||
232 | int i, frags = skb_shinfo(skb)->nr_frags; | ||
233 | int pages = 0; | ||
234 | |||
235 | for (i = 0; i < frags; i++) { | ||
236 | skb_frag_t *frag = skb_shinfo(skb)->frags + i; | ||
237 | unsigned long size = skb_frag_size(frag); | ||
238 | unsigned long offset = frag->page_offset; | ||
239 | |||
240 | /* Skip unused frames from start of page */ | ||
241 | offset &= ~PAGE_MASK; | ||
242 | pages += PFN_UP(offset + size); | ||
243 | } | ||
244 | return pages; | ||
245 | } | ||
246 | |||
247 | static int netvsc_get_slots(struct sk_buff *skb) | ||
248 | { | ||
249 | char *data = skb->data; | ||
250 | unsigned int offset = offset_in_page(data); | ||
251 | unsigned int len = skb_headlen(skb); | ||
252 | int slots; | ||
253 | int frag_slots; | ||
254 | |||
255 | slots = DIV_ROUND_UP(offset + len, PAGE_SIZE); | ||
256 | frag_slots = count_skb_frag_slots(skb); | ||
257 | return slots + frag_slots; | ||
258 | } | ||
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 | |||
143 | 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) |
144 | { | 290 | { |
145 | struct net_device_context *net_device_ctx = netdev_priv(net); | 291 | struct net_device_context *net_device_ctx = netdev_priv(net); |
146 | struct hv_netvsc_packet *packet; | 292 | struct hv_netvsc_packet *packet; |
147 | int ret; | 293 | int ret; |
148 | unsigned int i, num_pages, npg_data; | 294 | unsigned int num_data_pgs; |
149 | 295 | struct rndis_message *rndis_msg; | |
150 | /* Add multipages for skb->data and additional 2 for RNDIS */ | 296 | struct rndis_packet *rndis_pkt; |
151 | npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1) | 297 | u32 rndis_msg_size; |
152 | >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1; | 298 | bool isvlan; |
153 | num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2; | 299 | struct rndis_per_packet_info *ppi; |
300 | struct ndis_tcp_ip_checksum_info *csum_info; | ||
301 | struct ndis_tcp_lso_info *lso_info; | ||
302 | int hdr_offset; | ||
303 | u32 net_trans_info; | ||
304 | |||
305 | |||
306 | /* We will atmost need two pages to describe the rndis | ||
307 | * header. We can only transmit MAX_PAGE_BUFFER_COUNT number | ||
308 | * of pages in a single packet. | ||
309 | */ | ||
310 | num_data_pgs = netvsc_get_slots(skb) + 2; | ||
311 | if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) { | ||
312 | netdev_err(net, "Packet too big: %u\n", skb->len); | ||
313 | dev_kfree_skb(skb); | ||
314 | net->stats.tx_dropped++; | ||
315 | return NETDEV_TX_OK; | ||
316 | } | ||
154 | 317 | ||
155 | /* Allocate a netvsc packet based on # of frags. */ | 318 | /* Allocate a netvsc packet based on # of frags. */ |
156 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + | 319 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + |
157 | (num_pages * sizeof(struct hv_page_buffer)) + | 320 | (num_data_pgs * sizeof(struct hv_page_buffer)) + |
158 | sizeof(struct rndis_filter_packet) + | 321 | sizeof(struct rndis_message) + |
159 | NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); | 322 | NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); |
160 | if (!packet) { | 323 | if (!packet) { |
161 | /* out of memory, drop packet */ | 324 | /* out of memory, drop packet */ |
@@ -168,53 +331,111 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
168 | 331 | ||
169 | packet->vlan_tci = skb->vlan_tci; | 332 | packet->vlan_tci = skb->vlan_tci; |
170 | 333 | ||
171 | packet->extension = (void *)(unsigned long)packet + | 334 | packet->is_data_pkt = true; |
335 | packet->total_data_buflen = skb->len; | ||
336 | |||
337 | packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + | ||
172 | sizeof(struct hv_netvsc_packet) + | 338 | sizeof(struct hv_netvsc_packet) + |
173 | (num_pages * sizeof(struct hv_page_buffer)); | 339 | (num_data_pgs * sizeof(struct hv_page_buffer))); |
340 | |||
341 | /* Set the completion routine */ | ||
342 | packet->completion.send.send_completion = netvsc_xmit_completion; | ||
343 | packet->completion.send.send_completion_ctx = packet; | ||
344 | packet->completion.send.send_completion_tid = (unsigned long)skb; | ||
174 | 345 | ||
175 | /* If the rndis msg goes beyond 1 page, we will add 1 later */ | 346 | isvlan = packet->vlan_tci & VLAN_TAG_PRESENT; |
176 | packet->page_buf_cnt = num_pages - 1; | 347 | |
348 | /* Add the rndis header */ | ||
349 | rndis_msg = packet->rndis_msg; | ||
350 | rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; | ||
351 | rndis_msg->msg_len = packet->total_data_buflen; | ||
352 | rndis_pkt = &rndis_msg->msg.pkt; | ||
353 | rndis_pkt->data_offset = sizeof(struct rndis_packet); | ||
354 | rndis_pkt->data_len = packet->total_data_buflen; | ||
355 | rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); | ||
356 | |||
357 | rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); | ||
358 | |||
359 | if (isvlan) { | ||
360 | struct ndis_pkt_8021q_info *vlan; | ||
361 | |||
362 | rndis_msg_size += NDIS_VLAN_PPI_SIZE; | ||
363 | ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE, | ||
364 | IEEE_8021Q_INFO); | ||
365 | vlan = (struct ndis_pkt_8021q_info *)((void *)ppi + | ||
366 | ppi->ppi_offset); | ||
367 | vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK; | ||
368 | vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >> | ||
369 | VLAN_PRIO_SHIFT; | ||
370 | } | ||
177 | 371 | ||
178 | /* Initialize it from the skb */ | 372 | net_trans_info = get_net_transport_info(skb, &hdr_offset); |
179 | packet->total_data_buflen = skb->len; | 373 | if (net_trans_info == TRANSPORT_INFO_NOT_IP) |
374 | goto do_send; | ||
375 | |||
376 | /* | ||
377 | * Setup the sendside checksum offload only if this is not a | ||
378 | * GSO packet. | ||
379 | */ | ||
380 | if (skb_is_gso(skb)) | ||
381 | goto do_lso; | ||
382 | |||
383 | rndis_msg_size += NDIS_CSUM_PPI_SIZE; | ||
384 | ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, | ||
385 | TCPIP_CHKSUM_PKTINFO); | ||
386 | |||
387 | csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi + | ||
388 | ppi->ppi_offset); | ||
180 | 389 | ||
181 | /* Start filling in the page buffers starting after RNDIS buffer. */ | 390 | if (net_trans_info & (INFO_IPV4 << 16)) |
182 | packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; | 391 | csum_info->transmit.is_ipv4 = 1; |
183 | packet->page_buf[1].offset | ||
184 | = (unsigned long)skb->data & (PAGE_SIZE - 1); | ||
185 | if (npg_data == 1) | ||
186 | packet->page_buf[1].len = skb_headlen(skb); | ||
187 | else | 392 | else |
188 | packet->page_buf[1].len = PAGE_SIZE | 393 | csum_info->transmit.is_ipv6 = 1; |
189 | - packet->page_buf[1].offset; | 394 | |
190 | 395 | if (net_trans_info & INFO_TCP) { | |
191 | for (i = 2; i <= npg_data; i++) { | 396 | csum_info->transmit.tcp_checksum = 1; |
192 | packet->page_buf[i].pfn = virt_to_phys(skb->data | 397 | csum_info->transmit.tcp_header_offset = hdr_offset; |
193 | + PAGE_SIZE * (i-1)) >> PAGE_SHIFT; | 398 | } else if (net_trans_info & INFO_UDP) { |
194 | packet->page_buf[i].offset = 0; | 399 | csum_info->transmit.udp_checksum = 1; |
195 | packet->page_buf[i].len = PAGE_SIZE; | ||
196 | } | 400 | } |
197 | if (npg_data > 1) | 401 | goto do_send; |
198 | packet->page_buf[npg_data].len = (((unsigned long)skb->data | 402 | |
199 | + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1; | 403 | do_lso: |
200 | 404 | rndis_msg_size += NDIS_LSO_PPI_SIZE; | |
201 | /* Additional fragments are after SKB data */ | 405 | ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE, |
202 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 406 | TCP_LARGESEND_PKTINFO); |
203 | const skb_frag_t *f = &skb_shinfo(skb)->frags[i]; | 407 | |
204 | 408 | lso_info = (struct ndis_tcp_lso_info *)((void *)ppi + | |
205 | packet->page_buf[i+npg_data+1].pfn = | 409 | ppi->ppi_offset); |
206 | page_to_pfn(skb_frag_page(f)); | 410 | |
207 | packet->page_buf[i+npg_data+1].offset = f->page_offset; | 411 | lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; |
208 | packet->page_buf[i+npg_data+1].len = skb_frag_size(f); | 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); | ||
209 | } | 427 | } |
428 | lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset; | ||
429 | lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size; | ||
210 | 430 | ||
211 | /* Set the completion routine */ | 431 | do_send: |
212 | packet->completion.send.send_completion = netvsc_xmit_completion; | 432 | /* Start filling in the page buffers with the rndis hdr */ |
213 | packet->completion.send.send_completion_ctx = packet; | 433 | rndis_msg->msg_len += rndis_msg_size; |
214 | packet->completion.send.send_completion_tid = (unsigned long)skb; | 434 | packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, |
435 | skb, &packet->page_buf[0]); | ||
436 | |||
437 | ret = netvsc_send(net_device_ctx->device_ctx, packet); | ||
215 | 438 | ||
216 | ret = rndis_filter_send(net_device_ctx->device_ctx, | ||
217 | packet); | ||
218 | if (ret == 0) { | 439 | if (ret == 0) { |
219 | net->stats.tx_bytes += skb->len; | 440 | net->stats.tx_bytes += skb->len; |
220 | net->stats.tx_packets++; | 441 | net->stats.tx_packets++; |
@@ -264,7 +485,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, | |||
264 | * "wire" on the specified device. | 485 | * "wire" on the specified device. |
265 | */ | 486 | */ |
266 | int netvsc_recv_callback(struct hv_device *device_obj, | 487 | int netvsc_recv_callback(struct hv_device *device_obj, |
267 | struct hv_netvsc_packet *packet) | 488 | struct hv_netvsc_packet *packet, |
489 | struct ndis_tcp_ip_checksum_info *csum_info) | ||
268 | { | 490 | { |
269 | struct net_device *net; | 491 | struct net_device *net; |
270 | struct sk_buff *skb; | 492 | struct sk_buff *skb; |
@@ -291,7 +513,17 @@ int netvsc_recv_callback(struct hv_device *device_obj, | |||
291 | packet->total_data_buflen); | 513 | packet->total_data_buflen); |
292 | 514 | ||
293 | skb->protocol = eth_type_trans(skb, net); | 515 | skb->protocol = eth_type_trans(skb, net); |
294 | skb->ip_summed = CHECKSUM_NONE; | 516 | if (csum_info) { |
517 | /* We only look at the IP checksum here. | ||
518 | * Should we be dropping the packet if checksum | ||
519 | * failed? How do we deal with other checksums - TCP/UDP? | ||
520 | */ | ||
521 | if (csum_info->receive.ip_checksum_succeeded) | ||
522 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
523 | else | ||
524 | skb->ip_summed = CHECKSUM_NONE; | ||
525 | } | ||
526 | |||
295 | if (packet->vlan_tci & VLAN_TAG_PRESENT) | 527 | if (packet->vlan_tci & VLAN_TAG_PRESENT) |
296 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), | 528 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), |
297 | packet->vlan_tci); | 529 | packet->vlan_tci); |
@@ -327,7 +559,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) | |||
327 | if (nvdev == NULL || nvdev->destroy) | 559 | if (nvdev == NULL || nvdev->destroy) |
328 | return -ENODEV; | 560 | return -ENODEV; |
329 | 561 | ||
330 | if (nvdev->nvsp_version == NVSP_PROTOCOL_VERSION_2) | 562 | if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) |
331 | limit = NETVSC_MTU; | 563 | limit = NETVSC_MTU; |
332 | 564 | ||
333 | if (mtu < 68 || mtu > limit) | 565 | if (mtu < 68 || mtu > limit) |
@@ -452,9 +684,10 @@ static int netvsc_probe(struct hv_device *dev, | |||
452 | 684 | ||
453 | net->netdev_ops = &device_ops; | 685 | net->netdev_ops = &device_ops; |
454 | 686 | ||
455 | /* TODO: Add GSO and Checksum offload */ | 687 | net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM | |
456 | net->hw_features = 0; | 688 | NETIF_F_TSO; |
457 | net->features = NETIF_F_HW_VLAN_CTAG_TX; | 689 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | |
690 | NETIF_F_IP_CSUM | NETIF_F_TSO; | ||
458 | 691 | ||
459 | SET_ETHTOOL_OPS(net, ðtool_ops); | 692 | SET_ETHTOOL_OPS(net, ðtool_ops); |
460 | SET_NETDEV_DEV(net, &dev->device); | 693 | SET_NETDEV_DEV(net, &dev->device); |