From owner-svn-src-all@freebsd.org Wed Jul 27 06:52:44 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 904CBBA53EE; Wed, 27 Jul 2016 06:52:44 +0000 (UTC) (envelope-from sephe@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 51C0B1362; Wed, 27 Jul 2016 06:52:44 +0000 (UTC) (envelope-from sephe@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u6R6qhna080750; Wed, 27 Jul 2016 06:52:43 GMT (envelope-from sephe@FreeBSD.org) Received: (from sephe@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u6R6qht5080749; Wed, 27 Jul 2016 06:52:43 GMT (envelope-from sephe@FreeBSD.org) Message-Id: <201607270652.u6R6qht5080749@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: sephe set sender to sephe@FreeBSD.org using -f From: Sepherosa Ziehau Date: Wed, 27 Jul 2016 06:52:43 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r303368 - head/sys/dev/hyperv/vmbus X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 27 Jul 2016 06:52:44 -0000 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) {