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