Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 12 Oct 2016 05:09:27 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r307103 - stable/10/sys/dev/hyperv/vmbus
Message-ID:  <201610120509.u9C59Rjh008401@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Wed Oct 12 05:09:26 2016
New Revision: 307103
URL: https://svnweb.freebsd.org/changeset/base/307103

Log:
  MFC 303284,303329,303361,303362,303366,303368-303370
  
  303284
      hyperv/vmbus: Move bufring info definition to vmbus_brvar.h
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7282
  
  303329
      hyperv/vmbus: Nuke unnecessary accessor functions.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7303
  
  303361
      hyperv/vmbus: Initialize RX/TX bufring mutex at channel creation time
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7312
  
  303362
      hyperv/vmbus: Use different struct for RX/TX bufring.
  
      So that they can use suitable MP synchronization mechanism.
  
      While I'm here change the bufring init/read/write function names.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7313
  
  303366
      hyperv/vmbus: Update comment for bufring
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7314
  
  303368
      hyperv/vmbus: Cleanup TX bufring write process.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7315
  
  303369
      hyperv/vmbus: Stringent RX bufring data length checks.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7316
  
  303370
      hyperv/vmbus: Cleanup RX bufring read process.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7317

Modified:
  stable/10/sys/dev/hyperv/vmbus/hv_ring_buffer.c
  stable/10/sys/dev/hyperv/vmbus/vmbus_brvar.h
  stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c
  stable/10/sys/dev/hyperv/vmbus/vmbus_chanvar.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/vmbus/hv_ring_buffer.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_ring_buffer.c	Wed Oct 12 05:09:22 2016	(r307102)
+++ stable/10/sys/dev/hyperv/vmbus/hv_ring_buffer.c	Wed Oct 12 05:09:26 2016	(r307103)
@@ -37,32 +37,29 @@ __FBSDID("$FreeBSD$");
 #include <dev/hyperv/vmbus/vmbus_reg.h>
 #include <dev/hyperv/vmbus/vmbus_brvar.h>
 
-/* Amount of space to write to */
-#define	HV_BYTES_AVAIL_TO_WRITE(r, w, z)	\
-	((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w))
-
-static uint32_t	copy_to_ring_buffer(hv_vmbus_ring_buffer_info *ring_info,
-		    uint32_t start_write_offset, const uint8_t *src,
-		    uint32_t src_len);
-static uint32_t copy_from_ring_buffer(hv_vmbus_ring_buffer_info *ring_info,
-		    char *dest, uint32_t dest_len, uint32_t start_read_offset);
+/* Amount of space available for write */
+#define	VMBUS_BR_WAVAIL(r, w, z)	\
+	(((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w)))
+
+/* Increase bufing index */
+#define VMBUS_BR_IDXINC(idx, inc, sz)	(((idx) + (inc)) % (sz))
 
 static int
 vmbus_br_sysctl_state(SYSCTL_HANDLER_ARGS)
 {
-	const hv_vmbus_ring_buffer_info *br = arg1;
-	uint32_t rindex, windex, intr_mask, ravail, wavail;
+	const struct vmbus_br *br = arg1;
+	uint32_t rindex, windex, imask, ravail, wavail;
 	char state[256];
 
-	rindex = br->ring_buffer->br_rindex;
-	windex = br->ring_buffer->br_windex;
-	intr_mask = br->ring_buffer->br_imask;
-	wavail = HV_BYTES_AVAIL_TO_WRITE(rindex, windex, br->ring_data_size);
-	ravail = br->ring_data_size - wavail;
+	rindex = br->vbr_rindex;
+	windex = br->vbr_windex;
+	imask = br->vbr_imask;
+	wavail = VMBUS_BR_WAVAIL(rindex, windex, br->vbr_dsize);
+	ravail = br->vbr_dsize - wavail;
 
 	snprintf(state, sizeof(state),
-	    "rindex:%u windex:%u intr_mask:%u ravail:%u wavail:%u",
-	    rindex, windex, intr_mask, ravail, wavail);
+	    "rindex:%u windex:%u imask:%u ravail:%u wavail:%u",
+	    rindex, windex, imask, ravail, wavail);
 	return sysctl_handle_string(oidp, state, sizeof(state), req);
 }
 
@@ -79,25 +76,25 @@ vmbus_br_sysctl_state_bin(SYSCTL_HANDLER
 #define BR_STATE_WSPC	4
 #define BR_STATE_MAX	5
 
-	const hv_vmbus_ring_buffer_info *br = arg1;
+	const struct vmbus_br *br = arg1;
 	uint32_t rindex, windex, wavail, state[BR_STATE_MAX];
 
-	rindex = br->ring_buffer->br_rindex;
-	windex = br->ring_buffer->br_windex;
-	wavail = HV_BYTES_AVAIL_TO_WRITE(rindex, windex, br->ring_data_size);
+	rindex = br->vbr_rindex;
+	windex = br->vbr_windex;
+	wavail = VMBUS_BR_WAVAIL(rindex, windex, br->vbr_dsize);
 
 	state[BR_STATE_RIDX] = rindex;
 	state[BR_STATE_WIDX] = windex;
-	state[BR_STATE_IMSK] = br->ring_buffer->br_imask;
+	state[BR_STATE_IMSK] = br->vbr_imask;
 	state[BR_STATE_WSPC] = wavail;
-	state[BR_STATE_RSPC] = br->ring_data_size - wavail;
+	state[BR_STATE_RSPC] = br->vbr_dsize - wavail;
 
 	return sysctl_handle_opaque(oidp, state, sizeof(state), req);
 }
 
 void
 vmbus_br_sysctl_create(struct sysctl_ctx_list *ctx, struct sysctl_oid *br_tree,
-    hv_vmbus_ring_buffer_info *br, const char *name)
+    struct vmbus_br *br, const char *name)
 {
 	struct sysctl_oid *tree;
 	char desc[64];
@@ -118,342 +115,291 @@ vmbus_br_sysctl_create(struct sysctl_ctx
 	    br, 0, vmbus_br_sysctl_state_bin, "IU", desc);
 }
 
-/**
- * @brief Get number of bytes available to read and to write to
- * for the specified ring buffer
- */
-static __inline void
-get_ring_buffer_avail_bytes(hv_vmbus_ring_buffer_info *rbi, uint32_t *read,
-    uint32_t *write)
+void
+vmbus_rxbr_intr_mask(struct vmbus_rxbr *rbr)
 {
-	uint32_t read_loc, write_loc;
-
-	/*
-	 * Capture the read/write indices before they changed
-	 */
-	read_loc = rbi->ring_buffer->br_rindex;
-	write_loc = rbi->ring_buffer->br_windex;
-
-	*write = HV_BYTES_AVAIL_TO_WRITE(read_loc, write_loc,
-	    rbi->ring_data_size);
-	*read = rbi->ring_data_size - *write;
+	rbr->rxbr_imask = 1;
+	mb();
 }
 
-/**
- * @brief Get the next write location for the specified ring buffer
- */
 static __inline uint32_t
-get_next_write_location(hv_vmbus_ring_buffer_info *ring_info)
+vmbus_rxbr_avail(const struct vmbus_rxbr *rbr)
 {
-	return ring_info->ring_buffer->br_windex;
-}
+	uint32_t rindex, windex;
 
-/**
- * @brief Set the next write location for the specified ring buffer
- */
-static __inline void
-set_next_write_location(hv_vmbus_ring_buffer_info *ring_info,
-    uint32_t next_write_location)
-{
-	ring_info->ring_buffer->br_windex = next_write_location;
-}
+	/* Get snapshot */
+	rindex = rbr->rxbr_rindex;
+	windex = rbr->rxbr_windex;
 
-/**
- * @brief Get the next read location for the specified ring buffer
- */
-static __inline uint32_t
-get_next_read_location(hv_vmbus_ring_buffer_info *ring_info)
-{
-	return ring_info->ring_buffer->br_rindex;
+	return (rbr->rxbr_dsize -
+	    VMBUS_BR_WAVAIL(rindex, windex, rbr->rxbr_dsize));
 }
 
-/**
- * @brief Get the next read location + offset for the specified ring buffer.
- * This allows the caller to skip.
- */
-static __inline uint32_t
-get_next_read_location_with_offset(hv_vmbus_ring_buffer_info *ring_info,
-    uint32_t offset)
+uint32_t
+vmbus_rxbr_intr_unmask(struct vmbus_rxbr *rbr)
 {
-	uint32_t next = ring_info->ring_buffer->br_rindex;
+	rbr->rxbr_imask = 0;
+	mb();
 
-	next += offset;
-	next %= ring_info->ring_data_size;
-	return (next);
+	/*
+	 * Now check to see if the ring buffer is still empty.
+	 * If it is not, we raced and we need to process new
+	 * incoming channel packets.
+	 */
+	return vmbus_rxbr_avail(rbr);
 }
 
-/**
- * @brief Set the next read location for the specified ring buffer
- */
-static __inline void
-set_next_read_location(hv_vmbus_ring_buffer_info *ring_info,
-    uint32_t next_read_location)
+static void
+vmbus_br_setup(struct vmbus_br *br, void *buf, int blen)
 {
-	ring_info->ring_buffer->br_rindex = next_read_location;
+	br->vbr = buf;
+	br->vbr_dsize = blen - sizeof(struct vmbus_bufring);
 }
 
-/**
- * @brief Get the start of the ring buffer
- */
-static __inline void *
-get_ring_buffer(hv_vmbus_ring_buffer_info *ring_info)
+void
+vmbus_rxbr_init(struct vmbus_rxbr *rbr)
 {
-	return ring_info->ring_buffer->br_data;
+	mtx_init(&rbr->rxbr_lock, "vmbus_rxbr", NULL, MTX_SPIN);
 }
 
-/**
- * @brief Get the size of the ring buffer.
- */
-static __inline uint32_t
-get_ring_buffer_size(hv_vmbus_ring_buffer_info *ring_info)
+void
+vmbus_rxbr_deinit(struct vmbus_rxbr *rbr)
 {
-	return ring_info->ring_data_size;
+	mtx_destroy(&rbr->rxbr_lock);
 }
 
-/**
- * Get the read and write indices as uint64_t of the specified ring buffer.
- */
-static __inline uint64_t
-get_ring_buffer_indices(hv_vmbus_ring_buffer_info *ring_info)
+void
+vmbus_rxbr_setup(struct vmbus_rxbr *rbr, void *buf, int blen)
 {
-	return ((uint64_t)ring_info->ring_buffer->br_windex) << 32;
+	vmbus_br_setup(&rbr->rxbr, buf, blen);
 }
 
 void
-hv_ring_buffer_read_begin(hv_vmbus_ring_buffer_info *ring_info)
+vmbus_txbr_init(struct vmbus_txbr *tbr)
 {
-	ring_info->ring_buffer->br_imask = 1;
-	mb();
+	mtx_init(&tbr->txbr_lock, "vmbus_txbr", NULL, MTX_SPIN);
 }
 
-uint32_t
-hv_ring_buffer_read_end(hv_vmbus_ring_buffer_info *ring_info)
+void
+vmbus_txbr_deinit(struct vmbus_txbr *tbr)
 {
-	uint32_t read, write;
-
-	ring_info->ring_buffer->br_imask = 0;
-	mb();
+	mtx_destroy(&tbr->txbr_lock);
+}
 
-	/*
-	 * 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);
+void
+vmbus_txbr_setup(struct vmbus_txbr *tbr, void *buf, int blen)
+{
+	vmbus_br_setup(&tbr->txbr, buf, blen);
 }
 
 /*
- * 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.
+ * When we write to the ring buffer, check if the host needs to be
+ * signaled.
  *
- *	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.
+ * 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,
-    hv_vmbus_ring_buffer_info *rbi)
+static __inline boolean_t
+vmbus_txbr_need_signal(const struct vmbus_txbr *tbr, uint32_t old_windex)
 {
 	mb();
-	if (rbi->ring_buffer->br_imask)
+	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 == rbi->ring_buffer->br_rindex)
+	if (old_windex == tbr->txbr_rindex)
 		return (TRUE);
 
 	return (FALSE);
 }
 
-/**
- * @brief Initialize the ring buffer.
- */
-int
-hv_vmbus_ring_buffer_init(hv_vmbus_ring_buffer_info *ring_info, void *buffer,
-    uint32_t buffer_len)
+static __inline uint32_t
+vmbus_txbr_avail(const struct vmbus_txbr *tbr)
 {
-	memset(ring_info, 0, sizeof(hv_vmbus_ring_buffer_info));
-
-	ring_info->ring_buffer = buffer;
-	ring_info->ring_buffer->br_rindex = 0;
-	ring_info->ring_buffer->br_windex = 0;
+	uint32_t rindex, windex;
 
-	ring_info->ring_data_size = buffer_len - sizeof(struct vmbus_bufring);
-	mtx_init(&ring_info->ring_lock, "vmbus ring buffer", NULL, MTX_SPIN);
+	/* Get snapshot */
+	rindex = tbr->txbr_rindex;
+	windex = tbr->txbr_windex;
 
-	return (0);
+	return VMBUS_BR_WAVAIL(rindex, windex, tbr->txbr_dsize);
 }
 
-/**
- * @brief Cleanup the ring buffer.
- */
-void
-hv_ring_buffer_cleanup(hv_vmbus_ring_buffer_info *ring_info) 
+static __inline uint32_t
+vmbus_txbr_copyto(const struct vmbus_txbr *tbr, uint32_t windex,
+    const void *src0, uint32_t cplen)
 {
-	mtx_destroy(&ring_info->ring_lock);
+	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 = br_dsize - windex;
+
+		/* Wrap-around detected */
+		memcpy(br_data + windex, src, fraglen);
+		memcpy(br_data, src + fraglen, cplen - fraglen);
+	} else {
+		memcpy(br_data + windex, src, cplen);
+	}
+	return VMBUS_BR_IDXINC(windex, cplen, br_dsize);
 }
 
-/**
- * @brief Write to the ring buffer.
+/*
+ * 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
-hv_ring_buffer_write(hv_vmbus_ring_buffer_info *out_ring_info,
-    const struct iovec iov[], uint32_t iovlen, boolean_t *need_sig)
+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 byte_avail_to_read;
-	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 += iov[i].iov_len;
+	total += sizeof(save_windex);
 
-	total_bytes_to_write += sizeof(uint64_t);
-
-	mtx_lock_spin(&out_ring_info->ring_lock);
-
-	get_ring_buffer_avail_bytes(out_ring_info, &byte_avail_to_read,
-	    &byte_avail_to_write);
+	mtx_lock_spin(&tbr->txbr_lock);
 
 	/*
-	 * If there is only room for the packet, assume it is full.
-	 * Otherwise, the next time around, we think the ring buffer
-	 * is empty since the read index == write index
+	 * NOTE:
+	 * If this write is going to make br_windex same as br_rindex,
+	 * i.e. the available space for write is same as the write size,
+	 * 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) {
-		mtx_unlock_spin(&out_ring_info->ring_lock);
+	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;
+
 	/*
-	 * Write to the ring buffer
+	 * Copy the scattered channel packet to the TX bufring.
 	 */
-	next_write_location = get_next_write_location(out_ring_info);
-
-	old_write_location = next_write_location;
-
+	windex = old_windex;
 	for (i = 0; i < iovlen; i++) {
-		next_write_location = copy_to_ring_buffer(out_ring_info,
-		    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 previous packet start
+	 * Set the offset of the current channel packet.
 	 */
-	prev_indices = get_ring_buffer_indices(out_ring_info);
-
-	next_write_location = copy_to_ring_buffer(out_ring_info,
-	    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.
 	 * Full memory barrier before upding the write index. 
 	 */
 	mb();
 
 	/*
-	 * Now, update the write location
+	 * Update the write index _after_ the channel packet
+	 * is copied.
 	 */
-	set_next_write_location(out_ring_info, next_write_location);
+	tbr->txbr_windex = windex;
 
-	mtx_unlock_spin(&out_ring_info->ring_lock);
+	mtx_unlock_spin(&tbr->txbr_lock);
 
-	*need_sig = hv_ring_buffer_needsig_on_write(old_write_location,
-	    out_ring_info);
+	*need_sig = vmbus_txbr_need_signal(tbr, old_windex);
 
 	return (0);
 }
 
-/**
- * @brief Read without advancing the read index.
- */
-int
-hv_ring_buffer_peek(hv_vmbus_ring_buffer_info *in_ring_info, void *buffer,
-    uint32_t buffer_len)
+static __inline uint32_t
+vmbus_rxbr_copyfrom(const struct vmbus_rxbr *rbr, uint32_t rindex,
+    void *dst0, int cplen)
 {
-	uint32_t bytesAvailToWrite;
-	uint32_t bytesAvailToRead;
-	uint32_t nextReadLocation = 0;
-
-	mtx_lock_spin(&in_ring_info->ring_lock);
+	uint8_t *dst = dst0;
+	const uint8_t *br_data = rbr->rxbr_data;
+	uint32_t br_dsize = rbr->rxbr_dsize;
+
+	if (cplen > br_dsize - rindex) {
+		uint32_t fraglen = br_dsize - rindex;
+
+		/* Wrap-around detected. */
+		memcpy(dst, br_data + rindex, fraglen);
+		memcpy(dst + fraglen, br_data, cplen - fraglen);
+	} else {
+		memcpy(dst, br_data + rindex, cplen);
+	}
+	return VMBUS_BR_IDXINC(rindex, cplen, br_dsize);
+}
 
-	get_ring_buffer_avail_bytes(in_ring_info, &bytesAvailToRead,
-	    &bytesAvailToWrite);
+int
+vmbus_rxbr_peek(struct vmbus_rxbr *rbr, void *data, int dlen)
+{
+	mtx_lock_spin(&rbr->rxbr_lock);
 
 	/*
-	 * Make sure there is something to read
+	 * The requested data and the 64bits channel packet
+	 * offset should be there at least.
 	 */
-	if (bytesAvailToRead < buffer_len) {
-		mtx_unlock_spin(&in_ring_info->ring_lock);
+	if (vmbus_rxbr_avail(rbr) < dlen + sizeof(uint64_t)) {
+		mtx_unlock_spin(&rbr->rxbr_lock);
 		return (EAGAIN);
 	}
+	vmbus_rxbr_copyfrom(rbr, rbr->rxbr_rindex, data, dlen);
 
-	/*
-	 * Convert to byte offset
-	 */
-	nextReadLocation = get_next_read_location(in_ring_info);
-
-	nextReadLocation = copy_from_ring_buffer(in_ring_info,
-	    (char *)buffer, buffer_len, nextReadLocation);
-
-	mtx_unlock_spin(&in_ring_info->ring_lock);
+	mtx_unlock_spin(&rbr->rxbr_lock);
 
 	return (0);
 }
 
-/**
- * @brief Read and advance the read index.
+/*
+ * NOTE:
+ * We assume (dlen + skip) == sizeof(channel packet).
  */
 int
-hv_ring_buffer_read(hv_vmbus_ring_buffer_info *in_ring_info, void *buffer,
-    uint32_t buffer_len, uint32_t offset)
+vmbus_rxbr_read(struct vmbus_rxbr *rbr, void *data, int dlen, uint32_t skip)
 {
-	uint32_t bytes_avail_to_write;
-	uint32_t bytes_avail_to_read;
-	uint32_t next_read_location = 0;
-	uint64_t prev_indices = 0;
-
-	if (buffer_len <= 0)
-		return (EINVAL);
+	uint32_t rindex, br_dsize = rbr->rxbr_dsize;
 
-	mtx_lock_spin(&in_ring_info->ring_lock);
+	KASSERT(dlen + skip > 0, ("invalid dlen %d, offset %u", dlen, skip));
 
-	get_ring_buffer_avail_bytes(in_ring_info, &bytes_avail_to_read,
-	    &bytes_avail_to_write);
+	mtx_lock_spin(&rbr->rxbr_lock);
 
-	/*
-	 * Make sure there is something to read
-	 */
-	if (bytes_avail_to_read < buffer_len) {
-		mtx_unlock_spin(&in_ring_info->ring_lock);
+	if (vmbus_rxbr_avail(rbr) < dlen + skip + sizeof(uint64_t)) {
+		mtx_unlock_spin(&rbr->rxbr_lock);
 		return (EAGAIN);
 	}
 
-	next_read_location = get_next_read_location_with_offset(in_ring_info,
-	    offset);
-
-	next_read_location = copy_from_ring_buffer(in_ring_info, (char *)buffer,
-	    buffer_len, next_read_location);
+	/*
+	 * Copy channel packet from RX bufring.
+	 */
+	rindex = VMBUS_BR_IDXINC(rbr->rxbr_rindex, skip, br_dsize);
+	rindex = vmbus_rxbr_copyfrom(rbr, rindex, data, dlen);
 
-	next_read_location = copy_from_ring_buffer(in_ring_info,
-	    (char *)&prev_indices, sizeof(uint64_t), next_read_location);
+	/*
+	 * Discard this channel packet's 64bits offset, which is useless to us.
+	 */
+	rindex = VMBUS_BR_IDXINC(rindex, sizeof(uint64_t), br_dsize);
 
 	/*
+	 * XXX only compiler fence is needed.
 	 * Make sure all reads are done before we update the read index since
 	 * the writer may start writing to the read area once the read index
 	 * is updated.
@@ -461,67 +407,11 @@ hv_ring_buffer_read(hv_vmbus_ring_buffer
 	wmb();
 
 	/*
-	 * Update the read index
+	 * Update the read index _after_ the channel packet is fetched.
 	 */
-	set_next_read_location(in_ring_info, next_read_location);
+	rbr->rxbr_rindex = rindex;
 
-	mtx_unlock_spin(&in_ring_info->ring_lock);
+	mtx_unlock_spin(&rbr->rxbr_lock);
 
 	return (0);
 }
-
-/**
- * @brief Helper routine to copy from source to ring buffer.
- *
- * Assume there is enough room. Handles wrap-around in dest case only!
- */
-static uint32_t
-copy_to_ring_buffer(hv_vmbus_ring_buffer_info *ring_info,
-    uint32_t start_write_offset, const uint8_t *src, uint32_t src_len)
-{
-	char *ring_buffer = get_ring_buffer(ring_info);
-	uint32_t ring_buffer_size = get_ring_buffer_size(ring_info);
-	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);
-}
-
-/**
- * @brief Helper routine to copy to source from ring buffer.
- *
- * Assume there is enough room. Handles wrap-around in src case only!
- */
-static uint32_t
-copy_from_ring_buffer(hv_vmbus_ring_buffer_info *ring_info, char *dest,
-    uint32_t dest_len, uint32_t start_read_offset)
-{
-	uint32_t fragLen;
-	char *ring_buffer = get_ring_buffer(ring_info);
-	uint32_t ring_buffer_size = get_ring_buffer_size(ring_info);
-
-	if (dest_len > ring_buffer_size - start_read_offset) {
-		/* wrap-around detected at the src */
-		fragLen = ring_buffer_size - start_read_offset;
-		memcpy(dest, ring_buffer + start_read_offset, fragLen);
-		memcpy(dest + fragLen, ring_buffer, dest_len - fragLen);
-	} else {
-		memcpy(dest, ring_buffer + start_read_offset, dest_len);
-	}
-
-	start_read_offset += dest_len;
-	start_read_offset %= ring_buffer_size;
-
-	return (start_read_offset);
-}

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_brvar.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus_brvar.h	Wed Oct 12 05:09:22 2016	(r307102)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_brvar.h	Wed Oct 12 05:09:26 2016	(r307103)
@@ -28,58 +28,66 @@
  * $FreeBSD$
  */
 
-#ifndef __HYPERV_PRIV_H__
-#define __HYPERV_PRIV_H__
+#ifndef _VMBUS_BRVAR_H_
+#define _VMBUS_BRVAR_H_
 
 #include <sys/param.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
-#include <sys/sema.h>
 #include <sys/_iovec.h>
 
-#include <dev/hyperv/vmbus/vmbus_chanvar.h>
+struct vmbus_br {
+	struct vmbus_bufring	*vbr;
+	uint32_t		vbr_dsize;	/* total data size */
+};
+
+#define vbr_windex		vbr->br_windex
+#define vbr_rindex		vbr->br_rindex
+#define vbr_imask		vbr->br_imask
+#define vbr_data		vbr->br_data
+
+struct vmbus_rxbr {
+	struct mtx		rxbr_lock;
+	struct vmbus_br		rxbr;
+};
+
+#define rxbr_windex		rxbr.vbr_windex
+#define rxbr_rindex		rxbr.vbr_rindex
+#define rxbr_imask		rxbr.vbr_imask
+#define rxbr_data		rxbr.vbr_data
+#define rxbr_dsize		rxbr.vbr_dsize
+
+struct vmbus_txbr {
+	struct mtx		txbr_lock;
+	struct vmbus_br		txbr;
+};
+
+#define txbr_windex		txbr.vbr_windex
+#define txbr_rindex		txbr.vbr_rindex
+#define txbr_imask		txbr.vbr_imask
+#define txbr_data		txbr.vbr_data
+#define txbr_dsize		txbr.vbr_dsize
 
-struct vmbus_softc;
-
-/*
- * Private, VM Bus functions
- */
 struct sysctl_ctx_list;
 struct sysctl_oid;
 
-void	vmbus_br_sysctl_create(struct sysctl_ctx_list *ctx,
-	    struct sysctl_oid *br_tree, hv_vmbus_ring_buffer_info *br,
-	    const char *name);
-
-int			hv_vmbus_ring_buffer_init(
-				hv_vmbus_ring_buffer_info	*ring_info,
-				void				*buffer,
-				uint32_t			buffer_len);
-
-void			hv_ring_buffer_cleanup(
-				hv_vmbus_ring_buffer_info	*ring_info);
-
-int			hv_ring_buffer_write(
-				hv_vmbus_ring_buffer_info	*ring_info,
-				const struct iovec		iov[],
-				uint32_t			iovlen,
-				boolean_t			*need_sig);
-
-int			hv_ring_buffer_peek(
-				hv_vmbus_ring_buffer_info	*ring_info,
-				void				*buffer,
-				uint32_t			buffer_len);
-
-int			hv_ring_buffer_read(
-				hv_vmbus_ring_buffer_info	*ring_info,
-				void				*buffer,
-				uint32_t			buffer_len,
-				uint32_t			offset);
-
-void			hv_ring_buffer_read_begin(
-				hv_vmbus_ring_buffer_info	*ring_info);
-
-uint32_t		hv_ring_buffer_read_end(
-				hv_vmbus_ring_buffer_info	*ring_info);
+void		vmbus_br_sysctl_create(struct sysctl_ctx_list *ctx,
+		    struct sysctl_oid *br_tree, struct vmbus_br *br,
+		    const char *name);
+
+void		vmbus_rxbr_init(struct vmbus_rxbr *rbr);
+void		vmbus_rxbr_deinit(struct vmbus_rxbr *rbr);
+void		vmbus_rxbr_setup(struct vmbus_rxbr *rbr, void *buf, int blen);
+int		vmbus_rxbr_peek(struct vmbus_rxbr *rbr, void *data, int dlen);
+int		vmbus_rxbr_read(struct vmbus_rxbr *rbr, void *data, int dlen,
+		    uint32_t skip);
+void		vmbus_rxbr_intr_mask(struct vmbus_rxbr *rbr);
+uint32_t	vmbus_rxbr_intr_unmask(struct vmbus_rxbr *rbr);
+
+void		vmbus_txbr_init(struct vmbus_txbr *tbr);
+void		vmbus_txbr_deinit(struct vmbus_txbr *tbr);
+void		vmbus_txbr_setup(struct vmbus_txbr *tbr, void *buf, int blen);
+int		vmbus_txbr_write(struct vmbus_txbr *tbr,
+		    const struct iovec iov[], int iovlen, boolean_t *need_sig);
 
-#endif  /* __HYPERV_PRIV_H__ */
+#endif  /* _VMBUS_BRVAR_H_ */

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c	Wed Oct 12 05:09:22 2016	(r307102)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c	Wed Oct 12 05:09:26 2016	(r307103)
@@ -178,11 +178,11 @@ vmbus_chan_sysctl_create(struct vmbus_ch
 		/*
 		 * Create sysctl tree for RX bufring.
 		 */
-		vmbus_br_sysctl_create(ctx, br_tree, &chan->ch_rxbr, "rx");
+		vmbus_br_sysctl_create(ctx, br_tree, &chan->ch_rxbr.rxbr, "rx");
 		/*
 		 * Create sysctl tree for TX bufring.
 		 */
-		vmbus_br_sysctl_create(ctx, br_tree, &chan->ch_txbr, "tx");
+		vmbus_br_sysctl_create(ctx, br_tree, &chan->ch_txbr.txbr, "tx");
 	}
 }
 
@@ -239,9 +239,9 @@ vmbus_chan_open(struct vmbus_channel *ch
 	chan->ch_bufring = br;
 
 	/* TX bufring comes first */
-	hv_vmbus_ring_buffer_init(&chan->ch_txbr, br, txbr_size);
+	vmbus_txbr_setup(&chan->ch_txbr, br, txbr_size);
 	/* RX bufring immediately follows TX bufring */
-	hv_vmbus_ring_buffer_init(&chan->ch_rxbr, br + txbr_size, rxbr_size);
+	vmbus_rxbr_setup(&chan->ch_rxbr, br + txbr_size, rxbr_size);
 
 	/* Create sysctl tree for this channel */
 	vmbus_chan_sysctl_create(chan);
@@ -549,8 +549,6 @@ vmbus_chan_close_internal(struct vmbus_c
 	/*
 	 * Destroy the TX+RX bufrings.
 	 */
-	hv_ring_buffer_cleanup(&chan->ch_txbr);
-	hv_ring_buffer_cleanup(&chan->ch_rxbr);
 	if (chan->ch_bufring != NULL) {
 		hyperv_dmamem_free(&chan->ch_bufring_dma, chan->ch_bufring);
 		chan->ch_bufring = NULL;
@@ -620,7 +618,7 @@ vmbus_chan_send(struct vmbus_channel *ch
 	iov[2].iov_base = &pad;
 	iov[2].iov_len = pad_pktlen - pktlen;
 
-	error = hv_ring_buffer_write(&chan->ch_txbr, iov, 3, &send_evt);
+	error = vmbus_txbr_write(&chan->ch_txbr, iov, 3, &send_evt);
 	if (!error && send_evt)
 		vmbus_chan_signal_tx(chan);
 	return error;
@@ -660,7 +658,7 @@ vmbus_chan_send_sglist(struct vmbus_chan
 	iov[3].iov_base = &pad;
 	iov[3].iov_len = pad_pktlen - pktlen;
 
-	error = hv_ring_buffer_write(&chan->ch_txbr, iov, 4, &send_evt);
+	error = vmbus_txbr_write(&chan->ch_txbr, iov, 4, &send_evt);
 	if (!error && send_evt)
 		vmbus_chan_signal_tx(chan);
 	return error;
@@ -702,7 +700,7 @@ vmbus_chan_send_prplist(struct vmbus_cha
 	iov[3].iov_base = &pad;
 	iov[3].iov_len = pad_pktlen - pktlen;
 
-	error = hv_ring_buffer_write(&chan->ch_txbr, iov, 4, &send_evt);
+	error = vmbus_txbr_write(&chan->ch_txbr, iov, 4, &send_evt);
 	if (!error && send_evt)
 		vmbus_chan_signal_tx(chan);
 	return error;
@@ -715,7 +713,7 @@ vmbus_chan_recv(struct vmbus_channel *ch
 	struct vmbus_chanpkt_hdr pkt;
 	int error, dlen, hlen;
 
-	error = hv_ring_buffer_peek(&chan->ch_rxbr, &pkt, sizeof(pkt));
+	error = vmbus_rxbr_peek(&chan->ch_rxbr, &pkt, sizeof(pkt));
 	if (error)
 		return error;
 
@@ -732,8 +730,8 @@ vmbus_chan_recv(struct vmbus_channel *ch
 	*dlen0 = dlen;
 
 	/* Skip packet header */
-	error = hv_ring_buffer_read(&chan->ch_rxbr, data, dlen, hlen);
-	KASSERT(!error, ("hv_ring_buffer_read failed"));
+	error = vmbus_rxbr_read(&chan->ch_rxbr, data, dlen, hlen);
+	KASSERT(!error, ("vmbus_rxbr_read failed"));
 
 	return 0;
 }
@@ -745,7 +743,7 @@ vmbus_chan_recv_pkt(struct vmbus_channel
 	struct vmbus_chanpkt_hdr pkt;
 	int error, pktlen;
 
-	error = hv_ring_buffer_peek(&chan->ch_rxbr, &pkt, sizeof(pkt));
+	error = vmbus_rxbr_peek(&chan->ch_rxbr, &pkt, sizeof(pkt));
 	if (error)
 		return error;
 
@@ -758,8 +756,8 @@ vmbus_chan_recv_pkt(struct vmbus_channel
 	*pktlen0 = pktlen;
 
 	/* Include packet header */
-	error = hv_ring_buffer_read(&chan->ch_rxbr, pkt0, pktlen, 0);
-	KASSERT(!error, ("hv_ring_buffer_read failed"));
+	error = vmbus_rxbr_read(&chan->ch_rxbr, pkt0, pktlen, 0);
+	KASSERT(!error, ("vmbus_rxbr_read failed"));
 
 	return 0;
 }
@@ -788,12 +786,12 @@ vmbus_chan_task(void *xchan, int pending
 
 		cb(chan, cbarg);
 
-		left = hv_ring_buffer_read_end(&chan->ch_rxbr);
+		left = vmbus_rxbr_intr_unmask(&chan->ch_rxbr);
 		if (left == 0) {
 			/* No more data in RX bufring; done */
 			break;
 		}
-		hv_ring_buffer_read_begin(&chan->ch_rxbr);
+		vmbus_rxbr_intr_mask(&chan->ch_rxbr);
 	}
 }
 
@@ -835,7 +833,7 @@ vmbus_event_flags_proc(struct vmbus_soft
 				continue;
 
 			if (chan->ch_flags & VMBUS_CHAN_FLAG_BATCHREAD)
-				hv_ring_buffer_read_begin(&chan->ch_rxbr);
+				vmbus_rxbr_intr_mask(&chan->ch_rxbr);
 			taskqueue_enqueue(chan->ch_tq, &chan->ch_task);
 		}
 	}
@@ -914,6 +912,8 @@ vmbus_chan_alloc(struct vmbus_softc *sc)
 	mtx_init(&chan->ch_subchan_lock, "vmbus subchan", NULL, MTX_DEF);
 	TAILQ_INIT(&chan->ch_subchans);
 	TASK_INIT(&chan->ch_detach_task, 0, vmbus_chan_detach_task, chan);
+	vmbus_rxbr_init(&chan->ch_rxbr);
+	vmbus_txbr_init(&chan->ch_txbr);
 
 	return chan;
 }
@@ -926,6 +926,8 @@ vmbus_chan_free(struct vmbus_channel *ch
 	/* TODO: asset no longer on the vmbus channel list */
 	hyperv_dmamem_free(&chan->ch_monprm_dma, chan->ch_monprm);
 	mtx_destroy(&chan->ch_subchan_lock);
+	vmbus_rxbr_deinit(&chan->ch_rxbr);
+	vmbus_txbr_deinit(&chan->ch_txbr);
 	free(chan, M_DEVBUF);
 }
 

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_chanvar.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus_chanvar.h	Wed Oct 12 05:09:22 2016	(r307102)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_chanvar.h	Wed Oct 12 05:09:26 2016	(r307103)
@@ -39,12 +39,7 @@
 #include <dev/hyperv/include/hyperv.h>
 #include <dev/hyperv/include/hyperv_busdma.h>
 #include <dev/hyperv/include/vmbus.h>
-
-typedef struct {
-	struct vmbus_bufring	*ring_buffer;
-	struct mtx		ring_lock;
-	uint32_t		ring_data_size;	/* ring_size */
-} hv_vmbus_ring_buffer_info;
+#include <dev/hyperv/vmbus/vmbus_brvar.h>
 
 struct vmbus_channel {
 	/*
@@ -57,7 +52,7 @@ struct vmbus_channel {
 	/*
 	 * RX bufring; immediately following ch_txbr.
 	 */
-	hv_vmbus_ring_buffer_info	ch_rxbr;
+	struct vmbus_rxbr		ch_rxbr;
 
 	struct taskqueue		*ch_tq;
 	struct task			ch_task;
@@ -76,7 +71,7 @@ struct vmbus_channel {
 	 * TX bufring and following MNF/evtflags do _not_ fit in
 	 * one 64B cacheline.
 	 */
-	hv_vmbus_ring_buffer_info	ch_txbr __aligned(CACHE_LINE_SIZE);
+	struct vmbus_txbr		ch_txbr __aligned(CACHE_LINE_SIZE);
 	uint32_t			ch_txflags;	/* VMBUS_CHAN_TXF_ */
 
 	/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201610120509.u9C59Rjh008401>