summaryrefslogtreecommitdiffstats
path: root/sys/dev/hyperv/vmbus/hv_ring_buffer.c
diff options
context:
space:
mode:
authorwhu <whu@FreeBSD.org>2015-05-22 09:03:55 +0000
committerwhu <whu@FreeBSD.org>2015-05-22 09:03:55 +0000
commit30cd3b9808be2ed4002993166f0790b8f07d95d8 (patch)
treef2a61a02982282e7de44dcf271ef00cd723d44c5 /sys/dev/hyperv/vmbus/hv_ring_buffer.c
parentb453b295750133b89170fcb27025f932be66ad18 (diff)
downloadFreeBSD-src-30cd3b9808be2ed4002993166f0790b8f07d95d8.zip
FreeBSD-src-30cd3b9808be2ed4002993166f0790b8f07d95d8.tar.gz
MFC r282212:
Microsoft vmbus, storage and other related driver enhancements for HyperV. - Vmbus multi channel support. - Vector interrupt support. - Signal optimization. - Storvsc driver performance improvement. - Scatter and gather support for storvsc driver. - Minor bug fix for KVP driver. Thanks royger, jhb and delphij from FreeBSD community for the reviews and comments. Also thanks Hovy Xu from NetApp for the contributions to the storvsc driver. PR: 195238 Submitted by: whu Reviewed by: royger Approved by: royger Relnotes: yes Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D2575
Diffstat (limited to 'sys/dev/hyperv/vmbus/hv_ring_buffer.c')
-rw-r--r--sys/dev/hyperv/vmbus/hv_ring_buffer.c78
1 files changed, 75 insertions, 3 deletions
diff --git a/sys/dev/hyperv/vmbus/hv_ring_buffer.c b/sys/dev/hyperv/vmbus/hv_ring_buffer.c
index f7c1965..0e51ef7 100644
--- a/sys/dev/hyperv/vmbus/hv_ring_buffer.c
+++ b/sys/dev/hyperv/vmbus/hv_ring_buffer.c
@@ -26,6 +26,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/lock.h>
@@ -144,6 +146,69 @@ get_ring_buffer_indices(hv_vmbus_ring_buffer_info* ring_info)
return (uint64_t) ring_info->ring_buffer->write_index << 32;
}
+void
+hv_ring_buffer_read_begin(
+ hv_vmbus_ring_buffer_info* ring_info)
+{
+ ring_info->ring_buffer->interrupt_mask = 1;
+ mb();
+}
+
+uint32_t
+hv_ring_buffer_read_end(
+ hv_vmbus_ring_buffer_info* ring_info)
+{
+ uint32_t read, write;
+
+ ring_info->ring_buffer->interrupt_mask = 0;
+ mb();
+
+ /*
+ * Now check to see if the ring buffer is still empty.
+ * If it is not, we raced and we need to process new
+ * incoming messages.
+ */
+ get_ring_buffer_avail_bytes(ring_info, &read, &write);
+
+ return (read);
+}
+
+/*
+ * When we write to the ring buffer, check if the host needs to
+ * be signaled. Here is the details of this protocol:
+ *
+ * 1. The host guarantees that while it is draining the
+ * ring buffer, it will set the interrupt_mask to
+ * indicate it does not need to be interrupted when
+ * new data is placed.
+ *
+ * 2. The host guarantees that it will completely drain
+ * the ring buffer before exiting the read loop. Further,
+ * once the ring buffer is empty, it will clear the
+ * interrupt_mask and re-check to see if new data has
+ * arrived.
+ */
+static boolean_t
+hv_ring_buffer_needsig_on_write(
+ uint32_t old_write_location,
+ hv_vmbus_ring_buffer_info* rbi)
+{
+ mb();
+ if (rbi->ring_buffer->interrupt_mask)
+ return (FALSE);
+
+ /* Read memory barrier */
+ rmb();
+ /*
+ * This is the only case we need to signal when the
+ * ring transitions from being empty to non-empty.
+ */
+ if (old_write_location == rbi->ring_buffer->read_index)
+ return (TRUE);
+
+ return (FALSE);
+}
+
static uint32_t copy_to_ring_buffer(
hv_vmbus_ring_buffer_info* ring_info,
uint32_t start_write_offset,
@@ -204,11 +269,13 @@ int
hv_ring_buffer_write(
hv_vmbus_ring_buffer_info* out_ring_info,
hv_vmbus_sg_buffer_list sg_buffers[],
- uint32_t sg_buffer_count)
+ uint32_t sg_buffer_count,
+ boolean_t *need_sig)
{
int i = 0;
uint32_t byte_avail_to_write;
uint32_t byte_avail_to_read;
+ uint32_t old_write_location;
uint32_t total_bytes_to_write = 0;
volatile uint32_t next_write_location;
@@ -242,6 +309,8 @@ hv_ring_buffer_write(
*/
next_write_location = get_next_write_location(out_ring_info);
+ old_write_location = next_write_location;
+
for (i = 0; i < sg_buffer_count; i++) {
next_write_location = copy_to_ring_buffer(out_ring_info,
next_write_location, (char *) sg_buffers[i].data,
@@ -258,9 +327,9 @@ hv_ring_buffer_write(
(char *) &prev_indices, sizeof(uint64_t));
/*
- * Make sure we flush all writes before updating the writeIndex
+ * Full memory barrier before upding the write index.
*/
- wmb();
+ mb();
/*
* Now, update the write location
@@ -269,6 +338,9 @@ hv_ring_buffer_write(
mtx_unlock_spin(&out_ring_info->ring_lock);
+ *need_sig = hv_ring_buffer_needsig_on_write(old_write_location,
+ out_ring_info);
+
return (0);
}
OpenPOWER on IntegriCloud