svn commit: r303368 - head/sys/dev/hyperv/vmbus

Sepherosa Ziehau sephe at FreeBSD.org
Wed Jul 27 06:52:44 UTC 2016


Author: sephe
Date: Wed Jul 27 06:52:43 2016
New Revision: 303368
URL: https://svnweb.freebsd.org/changeset/base/303368

Log:
  hyperv/vmbus: Cleanup TX bufring write process.
  
  MFC after:	1 week
  Sponsored by:	Microsoft
  Differential Revision:	https://reviews.freebsd.org/D7315

Modified:
  head/sys/dev/hyperv/vmbus/hv_ring_buffer.c

Modified: head/sys/dev/hyperv/vmbus/hv_ring_buffer.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_ring_buffer.c	Wed Jul 27 06:49:16 2016	(r303367)
+++ head/sys/dev/hyperv/vmbus/hv_ring_buffer.c	Wed Jul 27 06:52:43 2016	(r303368)
@@ -38,9 +38,6 @@
 #define	VMBUS_BR_WAVAIL(r, w, z)	\
 	(((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w)))
 
-static uint32_t	copy_to_ring_buffer(const struct vmbus_txbr *tbr,
-		    uint32_t start_write_offset, const uint8_t *src,
-		    uint32_t src_len);
 static uint32_t copy_from_ring_buffer(const struct vmbus_rxbr *rbr,
 		    char *dest, uint32_t dest_len, uint32_t start_read_offset);
 
@@ -149,41 +146,6 @@ vmbus_rxbr_intr_unmask(struct vmbus_rxbr
 	return vmbus_rxbr_avail(rbr);
 }
 
-/*
- * When we write to the ring buffer, check if the host needs to be
- * signaled.
- *
- * The contract:
- * - The host guarantees that while it is draining the TX bufring,
- *   it will set the br_imask to indicate it does not need to be
- *   interrupted when new data are added.
- * - The host guarantees that it will completely drain the TX bufring
- *   before exiting the read loop.  Further, once the TX bufring is
- *   empty, it will clear the br_imask and re-check to see if new
- *   data have arrived.
- */
-static boolean_t
-hv_ring_buffer_needsig_on_write(uint32_t old_write_location,
-    const struct vmbus_txbr *tbr)
-{
-	mb();
-	if (tbr->txbr_imask)
-		return (FALSE);
-
-	/* XXX only compiler fence is needed */
-	/* 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 == tbr->txbr_rindex)
-		return (TRUE);
-
-	return (FALSE);
-}
-
 static void
 vmbus_br_setup(struct vmbus_br *br, void *buf, int blen)
 {
@@ -227,6 +189,40 @@ vmbus_txbr_setup(struct vmbus_txbr *tbr,
 	vmbus_br_setup(&tbr->txbr, buf, blen);
 }
 
+/*
+ * When we write to the ring buffer, check if the host needs to be
+ * signaled.
+ *
+ * The contract:
+ * - The host guarantees that while it is draining the TX bufring,
+ *   it will set the br_imask to indicate it does not need to be
+ *   interrupted when new data are added.
+ * - The host guarantees that it will completely drain the TX bufring
+ *   before exiting the read loop.  Further, once the TX bufring is
+ *   empty, it will clear the br_imask and re-check to see if new
+ *   data have arrived.
+ */
+static __inline boolean_t
+vmbus_txbr_need_signal(const struct vmbus_txbr *tbr, uint32_t old_windex)
+{
+	mb();
+	if (tbr->txbr_imask)
+		return (FALSE);
+
+	/* XXX only compiler fence is needed */
+	/* 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_windex == tbr->txbr_rindex)
+		return (TRUE);
+
+	return (FALSE);
+}
+
 static __inline uint32_t
 vmbus_txbr_avail(const struct vmbus_txbr *tbr)
 {
@@ -239,25 +235,52 @@ vmbus_txbr_avail(const struct vmbus_txbr
 	return VMBUS_BR_WAVAIL(rindex, windex, tbr->txbr_dsize);
 }
 
+static __inline uint32_t
+vmbus_txbr_copyto(const struct vmbus_txbr *tbr, uint32_t windex,
+    const void *src0, uint32_t cplen)
+{
+	const uint8_t *src = src0;
+	uint8_t *br_data = tbr->txbr_data;
+	uint32_t br_dsize = tbr->txbr_dsize;
+
+	if (cplen > br_dsize - windex) {
+		uint32_t fraglen;
+
+		/* Wrap-around detected! */
+		fraglen = br_dsize - windex;
+		memcpy(br_data + windex, src, fraglen);
+		memcpy(br_data, src + fraglen, cplen - fraglen);
+	} else {
+		memcpy(br_data + windex, src, cplen);
+	}
+
+	windex += cplen;
+	windex %= br_dsize;
+
+	return windex;
+}
+
+/*
+ * Write scattered channel packet to TX bufring.
+ *
+ * The offset of this channel packet is written as a 64bits value
+ * immediately after this channel packet.
+ */
 int
 vmbus_txbr_write(struct vmbus_txbr *tbr, const struct iovec iov[], int iovlen,
     boolean_t *need_sig)
 {
-	int i = 0;
-	uint32_t byte_avail_to_write;
-	uint32_t old_write_location;
-	uint32_t total_bytes_to_write = 0;
-	volatile uint32_t next_write_location;
-	uint64_t prev_indices = 0;
+	uint32_t old_windex, windex, total;
+	uint64_t save_windex;
+	int i;
 
+	total = 0;
 	for (i = 0; i < iovlen; i++)
-		total_bytes_to_write += iov[i].iov_len;
-	total_bytes_to_write += sizeof(uint64_t);
+		total += iov[i].iov_len;
+	total += sizeof(save_windex);
 
 	mtx_lock_spin(&tbr->txbr_lock);
 
-	byte_avail_to_write = vmbus_txbr_avail(tbr);
-
 	/*
 	 * NOTE:
 	 * If this write is going to make br_windex same as br_rindex,
@@ -265,29 +288,29 @@ vmbus_txbr_write(struct vmbus_txbr *tbr,
 	 * we can't do it then, since br_windex == br_rindex means that
 	 * the bufring is empty.
 	 */
-	if (byte_avail_to_write <= total_bytes_to_write) {
+	if (vmbus_txbr_avail(tbr) <= total) {
 		mtx_unlock_spin(&tbr->txbr_lock);
 		return (EAGAIN);
 	}
 
+	/* Save br_windex for later use */
+	old_windex = tbr->txbr_windex;
+
 	/*
 	 * Copy the scattered channel packet to the TX bufring.
 	 */
-	next_write_location = tbr->txbr_windex;
-
-	old_write_location = next_write_location;
-
+	windex = old_windex;
 	for (i = 0; i < iovlen; i++) {
-		next_write_location = copy_to_ring_buffer(tbr,
-		    next_write_location, iov[i].iov_base, iov[i].iov_len);
+		windex = vmbus_txbr_copyto(tbr, windex,
+		    iov[i].iov_base, iov[i].iov_len);
 	}
 
 	/*
 	 * Set the offset of the current channel packet.
 	 */
-	prev_indices = ((uint64_t)tbr->txbr_windex) << 32;
-	next_write_location = copy_to_ring_buffer(tbr,
-	    next_write_location, (char *)&prev_indices, sizeof(uint64_t));
+	save_windex = ((uint64_t)old_windex) << 32;
+	windex = vmbus_txbr_copyto(tbr, windex, &save_windex,
+	    sizeof(save_windex));
 
 	/*
 	 * XXX only compiler fence is needed.
@@ -296,13 +319,14 @@ vmbus_txbr_write(struct vmbus_txbr *tbr,
 	mb();
 
 	/*
-	 * Now, update the write index.
+	 * Update the write index _after_ the channel packet
+	 * is copied.
 	 */
-	tbr->txbr_windex = next_write_location;
+	tbr->txbr_windex = windex;
 
 	mtx_unlock_spin(&tbr->txbr_lock);
 
-	*need_sig = hv_ring_buffer_needsig_on_write(old_write_location, tbr);
+	*need_sig = vmbus_txbr_need_signal(tbr, old_windex);
 
 	return (0);
 }
@@ -380,29 +404,6 @@ vmbus_rxbr_read(struct vmbus_rxbr *rbr, 
 }
 
 static uint32_t
-copy_to_ring_buffer(const struct vmbus_txbr *tbr,
-    uint32_t start_write_offset, const uint8_t *src, uint32_t src_len)
-{
-	char *ring_buffer = tbr->txbr_data;
-	uint32_t ring_buffer_size = tbr->txbr_dsize;
-	uint32_t fragLen;
-
-	if (src_len > ring_buffer_size - start_write_offset) {
-		/* Wrap-around detected! */
-		fragLen = ring_buffer_size - start_write_offset;
-		memcpy(ring_buffer + start_write_offset, src, fragLen);
-		memcpy(ring_buffer, src + fragLen, src_len - fragLen);
-	} else {
-		memcpy(ring_buffer + start_write_offset, src, src_len);
-	}
-
-	start_write_offset += src_len;
-	start_write_offset %= ring_buffer_size;
-
-	return (start_write_offset);
-}
-
-static uint32_t
 copy_from_ring_buffer(const struct vmbus_rxbr *rbr, char *dest,
     uint32_t dest_len, uint32_t start_read_offset)
 {


More information about the svn-src-all mailing list