aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hv/ring_buffer.c31
-rw-r--r--drivers/net/hyperv/netvsc.c41
-rw-r--r--drivers/net/hyperv/netvsc_drv.c6
-rw-r--r--include/linux/hyperv.h27
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 */
48static inline void
49hv_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 */
439static 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
431static void netvsc_send_completion(struct hv_device *device, 449static 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 */
285static inline void
286hv_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 *