diff options
-rw-r--r-- | drivers/hv/ring_buffer.c | 31 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc.c | 41 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 6 | ||||
-rw-r--r-- | include/linux/hyperv.h | 27 |
4 files changed, 69 insertions, 36 deletions
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 8af25a097d75..7233c88f01b8 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c | |||
@@ -30,37 +30,6 @@ | |||
30 | #include "hyperv_vmbus.h" | 30 | #include "hyperv_vmbus.h" |
31 | 31 | ||
32 | 32 | ||
33 | /* #defines */ | ||
34 | |||
35 | |||
36 | /* Amount of space to write to */ | ||
37 | #define BYTES_AVAIL_TO_WRITE(r, w, z) \ | ||
38 | ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w)) | ||
39 | |||
40 | |||
41 | /* | ||
42 | * | ||
43 | * hv_get_ringbuffer_availbytes() | ||
44 | * | ||
45 | * Get number of bytes available to read and to write to | ||
46 | * for the specified ring buffer | ||
47 | */ | ||
48 | static inline void | ||
49 | hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi, | ||
50 | u32 *read, u32 *write) | ||
51 | { | ||
52 | u32 read_loc, write_loc; | ||
53 | |||
54 | smp_read_barrier_depends(); | ||
55 | |||
56 | /* Capture the read/write indices before they changed */ | ||
57 | read_loc = rbi->ring_buffer->read_index; | ||
58 | write_loc = rbi->ring_buffer->write_index; | ||
59 | |||
60 | *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->ring_datasize); | ||
61 | *read = rbi->ring_datasize - *write; | ||
62 | } | ||
63 | |||
64 | /* | 33 | /* |
65 | * hv_get_next_write_location() | 34 | * hv_get_next_write_location() |
66 | * | 35 | * |
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index d025c83cd12a..8b919471472f 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c | |||
@@ -428,6 +428,24 @@ int netvsc_device_remove(struct hv_device *device) | |||
428 | return 0; | 428 | return 0; |
429 | } | 429 | } |
430 | 430 | ||
431 | |||
432 | #define RING_AVAIL_PERCENT_HIWATER 20 | ||
433 | #define RING_AVAIL_PERCENT_LOWATER 10 | ||
434 | |||
435 | /* | ||
436 | * Get the percentage of available bytes to write in the ring. | ||
437 | * The return value is in range from 0 to 100. | ||
438 | */ | ||
439 | static inline u32 hv_ringbuf_avail_percent( | ||
440 | struct hv_ring_buffer_info *ring_info) | ||
441 | { | ||
442 | u32 avail_read, avail_write; | ||
443 | |||
444 | hv_get_ringbuffer_availbytes(ring_info, &avail_read, &avail_write); | ||
445 | |||
446 | return avail_write * 100 / ring_info->ring_datasize; | ||
447 | } | ||
448 | |||
431 | static void netvsc_send_completion(struct hv_device *device, | 449 | static void netvsc_send_completion(struct hv_device *device, |
432 | struct vmpacket_descriptor *packet) | 450 | struct vmpacket_descriptor *packet) |
433 | { | 451 | { |
@@ -455,6 +473,8 @@ static void netvsc_send_completion(struct hv_device *device, | |||
455 | complete(&net_device->channel_init_wait); | 473 | complete(&net_device->channel_init_wait); |
456 | } else if (nvsp_packet->hdr.msg_type == | 474 | } else if (nvsp_packet->hdr.msg_type == |
457 | NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) { | 475 | NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) { |
476 | int num_outstanding_sends; | ||
477 | |||
458 | /* Get the send context */ | 478 | /* Get the send context */ |
459 | nvsc_packet = (struct hv_netvsc_packet *)(unsigned long) | 479 | nvsc_packet = (struct hv_netvsc_packet *)(unsigned long) |
460 | packet->trans_id; | 480 | packet->trans_id; |
@@ -463,10 +483,14 @@ static void netvsc_send_completion(struct hv_device *device, | |||
463 | nvsc_packet->completion.send.send_completion( | 483 | nvsc_packet->completion.send.send_completion( |
464 | nvsc_packet->completion.send.send_completion_ctx); | 484 | nvsc_packet->completion.send.send_completion_ctx); |
465 | 485 | ||
466 | atomic_dec(&net_device->num_outstanding_sends); | 486 | num_outstanding_sends = |
487 | atomic_dec_return(&net_device->num_outstanding_sends); | ||
467 | 488 | ||
468 | if (netif_queue_stopped(ndev) && !net_device->start_remove) | 489 | if (netif_queue_stopped(ndev) && !net_device->start_remove && |
469 | netif_wake_queue(ndev); | 490 | (hv_ringbuf_avail_percent(&device->channel->outbound) |
491 | > RING_AVAIL_PERCENT_HIWATER || | ||
492 | num_outstanding_sends < 1)) | ||
493 | netif_wake_queue(ndev); | ||
470 | } else { | 494 | } else { |
471 | netdev_err(ndev, "Unknown send completion packet type- " | 495 | netdev_err(ndev, "Unknown send completion packet type- " |
472 | "%d received!!\n", nvsp_packet->hdr.msg_type); | 496 | "%d received!!\n", nvsp_packet->hdr.msg_type); |
@@ -519,10 +543,19 @@ int netvsc_send(struct hv_device *device, | |||
519 | 543 | ||
520 | if (ret == 0) { | 544 | if (ret == 0) { |
521 | atomic_inc(&net_device->num_outstanding_sends); | 545 | atomic_inc(&net_device->num_outstanding_sends); |
546 | if (hv_ringbuf_avail_percent(&device->channel->outbound) < | ||
547 | RING_AVAIL_PERCENT_LOWATER) { | ||
548 | netif_stop_queue(ndev); | ||
549 | if (atomic_read(&net_device-> | ||
550 | num_outstanding_sends) < 1) | ||
551 | netif_wake_queue(ndev); | ||
552 | } | ||
522 | } else if (ret == -EAGAIN) { | 553 | } else if (ret == -EAGAIN) { |
523 | netif_stop_queue(ndev); | 554 | netif_stop_queue(ndev); |
524 | if (atomic_read(&net_device->num_outstanding_sends) < 1) | 555 | if (atomic_read(&net_device->num_outstanding_sends) < 1) { |
525 | netif_wake_queue(ndev); | 556 | netif_wake_queue(ndev); |
557 | ret = -ENOSPC; | ||
558 | } | ||
526 | } else { | 559 | } else { |
527 | netdev_err(ndev, "Unable to send packet %p ret %d\n", | 560 | netdev_err(ndev, "Unable to send packet %p ret %d\n", |
528 | packet, ret); | 561 | packet, ret); |
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index dd294783b5c5..a0cc12786be4 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -224,9 +224,13 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
224 | net->stats.tx_packets++; | 224 | net->stats.tx_packets++; |
225 | } else { | 225 | } else { |
226 | kfree(packet); | 226 | kfree(packet); |
227 | if (ret != -EAGAIN) { | ||
228 | dev_kfree_skb_any(skb); | ||
229 | net->stats.tx_dropped++; | ||
230 | } | ||
227 | } | 231 | } |
228 | 232 | ||
229 | return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK; | 233 | return (ret == -EAGAIN) ? NETDEV_TX_BUSY : NETDEV_TX_OK; |
230 | } | 234 | } |
231 | 235 | ||
232 | /* | 236 | /* |
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 5852545e6bba..6af8738ae7e9 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h | |||
@@ -274,6 +274,33 @@ struct hv_ring_buffer_debug_info { | |||
274 | u32 bytes_avail_towrite; | 274 | u32 bytes_avail_towrite; |
275 | }; | 275 | }; |
276 | 276 | ||
277 | |||
278 | /* | ||
279 | * | ||
280 | * hv_get_ringbuffer_availbytes() | ||
281 | * | ||
282 | * Get number of bytes available to read and to write to | ||
283 | * for the specified ring buffer | ||
284 | */ | ||
285 | static inline void | ||
286 | hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi, | ||
287 | u32 *read, u32 *write) | ||
288 | { | ||
289 | u32 read_loc, write_loc, dsize; | ||
290 | |||
291 | smp_read_barrier_depends(); | ||
292 | |||
293 | /* Capture the read/write indices before they changed */ | ||
294 | read_loc = rbi->ring_buffer->read_index; | ||
295 | write_loc = rbi->ring_buffer->write_index; | ||
296 | dsize = rbi->ring_datasize; | ||
297 | |||
298 | *write = write_loc >= read_loc ? dsize - (write_loc - read_loc) : | ||
299 | read_loc - write_loc; | ||
300 | *read = dsize - *write; | ||
301 | } | ||
302 | |||
303 | |||
277 | /* | 304 | /* |
278 | * We use the same version numbering for all Hyper-V modules. | 305 | * We use the same version numbering for all Hyper-V modules. |
279 | * | 306 | * |