aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2012-12-01 09:46:36 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-17 13:46:39 -0500
commit98fa8cf4bcc79cb14de8fd815bbcd00dcbd7b20e (patch)
tree0d48abd179e49709cdac7e28eb853a653df7fbe2
parentf878f3d59ed26f489add852ed6d5c8e5f3bbb1aa (diff)
Drivers: hv: Optimize the signaling on the write path
The host has already implemented the "read" side optimizations. Leverage that to optimize "write" side signaling. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/hv/channel.c15
-rw-r--r--drivers/hv/hyperv_vmbus.h2
-rw-r--r--drivers/hv/ring_buffer.c42
3 files changed, 49 insertions, 10 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 773a2f25a8f0..727c5f1d6acf 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -564,6 +564,7 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
564 struct scatterlist bufferlist[3]; 564 struct scatterlist bufferlist[3];
565 u64 aligned_data = 0; 565 u64 aligned_data = 0;
566 int ret; 566 int ret;
567 bool signal = false;
567 568
568 569
569 /* Setup the descriptor */ 570 /* Setup the descriptor */
@@ -580,9 +581,9 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
580 sg_set_buf(&bufferlist[2], &aligned_data, 581 sg_set_buf(&bufferlist[2], &aligned_data,
581 packetlen_aligned - packetlen); 582 packetlen_aligned - packetlen);
582 583
583 ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3); 584 ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
584 585
585 if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound)) 586 if (ret == 0 && signal)
586 vmbus_setevent(channel); 587 vmbus_setevent(channel);
587 588
588 return ret; 589 return ret;
@@ -606,6 +607,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
606 u32 packetlen_aligned; 607 u32 packetlen_aligned;
607 struct scatterlist bufferlist[3]; 608 struct scatterlist bufferlist[3];
608 u64 aligned_data = 0; 609 u64 aligned_data = 0;
610 bool signal = false;
609 611
610 if (pagecount > MAX_PAGE_BUFFER_COUNT) 612 if (pagecount > MAX_PAGE_BUFFER_COUNT)
611 return -EINVAL; 613 return -EINVAL;
@@ -641,9 +643,9 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
641 sg_set_buf(&bufferlist[2], &aligned_data, 643 sg_set_buf(&bufferlist[2], &aligned_data,
642 packetlen_aligned - packetlen); 644 packetlen_aligned - packetlen);
643 645
644 ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3); 646 ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
645 647
646 if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound)) 648 if (ret == 0 && signal)
647 vmbus_setevent(channel); 649 vmbus_setevent(channel);
648 650
649 return ret; 651 return ret;
@@ -665,6 +667,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
665 u32 packetlen_aligned; 667 u32 packetlen_aligned;
666 struct scatterlist bufferlist[3]; 668 struct scatterlist bufferlist[3];
667 u64 aligned_data = 0; 669 u64 aligned_data = 0;
670 bool signal = false;
668 u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset, 671 u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
669 multi_pagebuffer->len); 672 multi_pagebuffer->len);
670 673
@@ -703,9 +706,9 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
703 sg_set_buf(&bufferlist[2], &aligned_data, 706 sg_set_buf(&bufferlist[2], &aligned_data,
704 packetlen_aligned - packetlen); 707 packetlen_aligned - packetlen);
705 708
706 ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3); 709 ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
707 710
708 if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound)) 711 if (ret == 0 && signal)
709 vmbus_setevent(channel); 712 vmbus_setevent(channel);
710 713
711 return ret; 714 return ret;
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 3184f6ff4e74..895c898812bd 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -555,7 +555,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
555 555
556int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info, 556int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
557 struct scatterlist *sglist, 557 struct scatterlist *sglist,
558 u32 sgcount); 558 u32 sgcount, bool *signal);
559 559
560int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer, 560int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
561 u32 buflen); 561 u32 buflen);
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 001079287709..9bc55f0dcf47 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -53,6 +53,37 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi)
53 return read; 53 return read;
54} 54}
55 55
56/*
57 * When we write to the ring buffer, check if the host needs to
58 * be signaled. Here is the details of this protocol:
59 *
60 * 1. The host guarantees that while it is draining the
61 * ring buffer, it will set the interrupt_mask to
62 * indicate it does not need to be interrupted when
63 * new data is placed.
64 *
65 * 2. The host guarantees that it will completely drain
66 * the ring buffer before exiting the read loop. Further,
67 * once the ring buffer is empty, it will clear the
68 * interrupt_mask and re-check to see if new data has
69 * arrived.
70 */
71
72static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
73{
74 if (rbi->ring_buffer->interrupt_mask)
75 return false;
76
77 /*
78 * This is the only case we need to signal when the
79 * ring transitions from being empty to non-empty.
80 */
81 if (old_write == rbi->ring_buffer->read_index)
82 return true;
83
84 return false;
85}
86
56 87
57/* 88/*
58 * hv_get_next_write_location() 89 * hv_get_next_write_location()
@@ -322,7 +353,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
322 * 353 *
323 */ 354 */
324int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, 355int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
325 struct scatterlist *sglist, u32 sgcount) 356 struct scatterlist *sglist, u32 sgcount, bool *signal)
326{ 357{
327 int i = 0; 358 int i = 0;
328 u32 bytes_avail_towrite; 359 u32 bytes_avail_towrite;
@@ -331,6 +362,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
331 362
332 struct scatterlist *sg; 363 struct scatterlist *sg;
333 u32 next_write_location; 364 u32 next_write_location;
365 u32 old_write;
334 u64 prev_indices = 0; 366 u64 prev_indices = 0;
335 unsigned long flags; 367 unsigned long flags;
336 368
@@ -359,6 +391,8 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
359 /* Write to the ring buffer */ 391 /* Write to the ring buffer */
360 next_write_location = hv_get_next_write_location(outring_info); 392 next_write_location = hv_get_next_write_location(outring_info);
361 393
394 old_write = next_write_location;
395
362 for_each_sg(sglist, sg, sgcount, i) 396 for_each_sg(sglist, sg, sgcount, i)
363 { 397 {
364 next_write_location = hv_copyto_ringbuffer(outring_info, 398 next_write_location = hv_copyto_ringbuffer(outring_info,
@@ -375,14 +409,16 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
375 &prev_indices, 409 &prev_indices,
376 sizeof(u64)); 410 sizeof(u64));
377 411
378 /* Make sure we flush all writes before updating the writeIndex */ 412 /* Issue a full memory barrier before updating the write index */
379 smp_wmb(); 413 smp_mb();
380 414
381 /* Now, update the write location */ 415 /* Now, update the write location */
382 hv_set_next_write_location(outring_info, next_write_location); 416 hv_set_next_write_location(outring_info, next_write_location);
383 417
384 418
385 spin_unlock_irqrestore(&outring_info->ring_lock, flags); 419 spin_unlock_irqrestore(&outring_info->ring_lock, flags);
420
421 *signal = hv_need_to_signal(old_write, outring_info);
386 return 0; 422 return 0;
387} 423}
388 424