aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaiyang Zhang <haiyangz@microsoft.com>2012-03-27 09:20:45 -0400
committerDavid S. Miller <davem@davemloft.net>2012-04-03 17:47:15 -0400
commit33be96e47cc27f2f1a753a0707b02a73df8c8d46 (patch)
tree2b0361f4d39a14e2ddd0d23e66656e6174b3cb71
parentede7193d4fdca98178240500d8684dbc139ca26f (diff)
net/hyperv: Add flow control based on hi/low watermark
In the existing code, we only stop queue when the ringbuffer is full, so the current packet has to be dropped or retried from upper layer. This patch stops the tx queue when available ringbuffer is below the low watermark. So the ringbuffer still has small amount of space available for the current packet. This will reduce the overhead of retries on sending. Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Reviewed-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-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 *