xref: /freebsd/sys/dev/hyperv/vmbus/vmbus_br.c (revision 3494f7c0)
1 /*-
2  * Copyright (c) 2009-2012,2016 Microsoft Corp.
3  * Copyright (c) 2012 NetApp Inc.
4  * Copyright (c) 2012 Citrix Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/lock.h>
31 #include <sys/mutex.h>
32 #include <sys/sysctl.h>
33 
34 #include <dev/hyperv/vmbus/vmbus_reg.h>
35 #include <dev/hyperv/vmbus/vmbus_brvar.h>
36 
37 /* Amount of space available for write */
38 #define	VMBUS_BR_WAVAIL(r, w, z)	\
39 	(((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w)))
40 
41 /* Increase bufing index */
42 #define VMBUS_BR_IDXINC(idx, inc, sz)	(((idx) + (inc)) % (sz))
43 
44 static int			vmbus_br_sysctl_state(SYSCTL_HANDLER_ARGS);
45 static int			vmbus_br_sysctl_state_bin(SYSCTL_HANDLER_ARGS);
46 static void			vmbus_br_setup(struct vmbus_br *, void *, int);
47 
48 static int
49 vmbus_br_sysctl_state(SYSCTL_HANDLER_ARGS)
50 {
51 	const struct vmbus_br *br = arg1;
52 	uint32_t rindex, windex, imask, psndsz, fvalue, ravail, wavail;
53 	uint64_t intrcnt;
54 	char state[256];
55 
56 	intrcnt = br->vbr_intrcnt;
57 	rindex = br->vbr_rindex;
58 	windex = br->vbr_windex;
59 	imask = br->vbr_imask;
60 	psndsz = br->vbr_psndsz;
61 	fvalue = br->vbr_fvalue;
62 	wavail = VMBUS_BR_WAVAIL(rindex, windex, br->vbr_dsize);
63 	ravail = br->vbr_dsize - wavail;
64 
65 	snprintf(state, sizeof(state),
66 	    "intrcnt:%ju rindex:%u windex:%u imask:%u psndsz:%u fvalue:%u "
67 	    "ravail:%u wavail:%u",
68 	    (uintmax_t)intrcnt, rindex, windex, imask, psndsz, fvalue,
69 	    ravail, wavail);
70 	return sysctl_handle_string(oidp, state, sizeof(state), req);
71 }
72 
73 /*
74  * Binary bufring states.
75  */
76 static int
77 vmbus_br_sysctl_state_bin(SYSCTL_HANDLER_ARGS)
78 {
79 #define BR_STATE_RIDX	0
80 #define BR_STATE_WIDX	1
81 #define BR_STATE_IMSK	2
82 #define BR_STATE_PSSZ	3
83 #define BR_STATE_FVAL	4
84 #define BR_STATE_RSPC	5
85 #define BR_STATE_WSPC	6
86 #define BR_STATE_MAX	7
87 
88 	const struct vmbus_br *br = arg1;
89 	uint32_t rindex, windex, wavail, state[BR_STATE_MAX];
90 
91 	rindex = br->vbr_rindex;
92 	windex = br->vbr_windex;
93 	wavail = VMBUS_BR_WAVAIL(rindex, windex, br->vbr_dsize);
94 
95 	state[BR_STATE_RIDX] = rindex;
96 	state[BR_STATE_WIDX] = windex;
97 	state[BR_STATE_IMSK] = br->vbr_imask;
98 	state[BR_STATE_PSSZ] = br->vbr_psndsz;
99 	state[BR_STATE_FVAL] = br->vbr_fvalue;
100 	state[BR_STATE_WSPC] = wavail;
101 	state[BR_STATE_RSPC] = br->vbr_dsize - wavail;
102 
103 	return sysctl_handle_opaque(oidp, state, sizeof(state), req);
104 }
105 
106 void
107 vmbus_br_sysctl_create(struct sysctl_ctx_list *ctx, struct sysctl_oid *br_tree,
108     struct vmbus_br *br, const char *name)
109 {
110 	struct sysctl_oid *tree;
111 	char desc[64];
112 
113 	tree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(br_tree), OID_AUTO,
114 	    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
115 	if (tree == NULL)
116 		return;
117 
118 	snprintf(desc, sizeof(desc), "%s state", name);
119 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "state",
120 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
121 	    br, 0, vmbus_br_sysctl_state, "A", desc);
122 
123 	snprintf(desc, sizeof(desc), "%s binary state", name);
124 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "state_bin",
125 	    CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
126 	    br, 0, vmbus_br_sysctl_state_bin, "IU", desc);
127 }
128 
129 void
130 vmbus_rxbr_intr_mask(struct vmbus_rxbr *rbr)
131 {
132 	rbr->rxbr_imask = 1;
133 	mb();
134 }
135 
136 static __inline uint32_t
137 vmbus_rxbr_avail(const struct vmbus_rxbr *rbr)
138 {
139 	uint32_t rindex, windex;
140 
141 	/* Get snapshot */
142 	rindex = atomic_load_acq_32(&rbr->rxbr_rindex);
143 	windex = atomic_load_acq_32(&rbr->rxbr_windex);
144 
145 	return (rbr->rxbr_dsize -
146 	    VMBUS_BR_WAVAIL(rindex, windex, rbr->rxbr_dsize));
147 }
148 
149 uint32_t
150 vmbus_rxbr_available(const struct vmbus_rxbr *rbr)
151 {
152 	return (vmbus_rxbr_avail(rbr));
153 }
154 
155 uint32_t
156 vmbus_rxbr_intr_unmask(struct vmbus_rxbr *rbr)
157 {
158 	rbr->rxbr_imask = 0;
159 	mb();
160 
161 	/*
162 	 * Now check to see if the ring buffer is still empty.
163 	 * If it is not, we raced and we need to process new
164 	 * incoming channel packets.
165 	 */
166 	return vmbus_rxbr_avail(rbr);
167 }
168 
169 static void
170 vmbus_br_setup(struct vmbus_br *br, void *buf, int blen)
171 {
172 	br->vbr = buf;
173 	br->vbr_dsize = blen - sizeof(struct vmbus_bufring);
174 }
175 
176 void
177 vmbus_rxbr_init(struct vmbus_rxbr *rbr)
178 {
179 	mtx_init(&rbr->rxbr_lock, "vmbus_rxbr", NULL, MTX_SPIN);
180 }
181 
182 void
183 vmbus_rxbr_deinit(struct vmbus_rxbr *rbr)
184 {
185 	mtx_destroy(&rbr->rxbr_lock);
186 }
187 
188 void
189 vmbus_rxbr_setup(struct vmbus_rxbr *rbr, void *buf, int blen)
190 {
191 	vmbus_br_setup(&rbr->rxbr, buf, blen);
192 }
193 
194 static __inline boolean_t
195 vmbus_rxbr_need_signal(const struct vmbus_rxbr *rbr, uint32_t bytes_read)
196 {
197 	uint32_t pending_snd_sz, canwrite_size;
198 
199 	/* No need to signal if host doesn't want us to */
200 	if (!rbr->rxbr_fpsndsz)
201 		return false;
202 
203 	mb();
204 
205 	pending_snd_sz = rbr->rxbr_psndsz;
206 	/* No need to signal if host sets pending_snd_sz to 0 */
207 	if (!pending_snd_sz)
208 		return false;
209 
210 	mb();
211 
212 	canwrite_size = rbr->rxbr_dsize - vmbus_rxbr_avail(rbr);
213 
214 	/* No need to signal if br already has enough space before read */
215 	if (canwrite_size - bytes_read > pending_snd_sz)
216 		return false;
217 
218 	/*
219 	 * No need to signal if still doesn't have enough space
220 	 * asked by host
221 	 */
222 	if (canwrite_size <= pending_snd_sz)
223 		return false;
224 
225 	return true;
226 }
227 
228 void
229 vmbus_txbr_init(struct vmbus_txbr *tbr)
230 {
231 	mtx_init(&tbr->txbr_lock, "vmbus_txbr", NULL, MTX_SPIN);
232 }
233 
234 void
235 vmbus_txbr_deinit(struct vmbus_txbr *tbr)
236 {
237 	mtx_destroy(&tbr->txbr_lock);
238 }
239 
240 void
241 vmbus_txbr_setup(struct vmbus_txbr *tbr, void *buf, int blen)
242 {
243 	vmbus_br_setup(&tbr->txbr, buf, blen);
244 
245 	/* Set feature bit enabling flow control */
246 	tbr->txbr_fpsndsz = 1;
247 }
248 
249 uint32_t
250 vmbus_txbr_get_imask(const struct vmbus_txbr *tbr)
251 {
252 	mb();
253 
254 	return(tbr->txbr_imask);
255 }
256 
257 void
258 vmbus_txbr_set_pending_snd_sz(struct vmbus_txbr *tbr, uint32_t size)
259 {
260 	tbr->txbr_psndsz = size;
261 }
262 
263 /*
264  * When we write to the ring buffer, check if the host needs to be
265  * signaled.
266  *
267  * The contract:
268  * - The host guarantees that while it is draining the TX bufring,
269  *   it will set the br_imask to indicate it does not need to be
270  *   interrupted when new data are added.
271  * - The host guarantees that it will completely drain the TX bufring
272  *   before exiting the read loop.  Further, once the TX bufring is
273  *   empty, it will clear the br_imask and re-check to see if new
274  *   data have arrived.
275  */
276 static __inline boolean_t
277 vmbus_txbr_need_signal(const struct vmbus_txbr *tbr, uint32_t old_windex)
278 {
279 	mb();
280 	if (tbr->txbr_imask)
281 		return (FALSE);
282 
283 	__compiler_membar();
284 
285 	/*
286 	 * This is the only case we need to signal when the
287 	 * ring transitions from being empty to non-empty.
288 	 */
289 	if (old_windex == atomic_load_acq_32(&tbr->txbr_rindex))
290 		return (TRUE);
291 
292 	return (FALSE);
293 }
294 
295 static __inline uint32_t
296 vmbus_txbr_avail(const struct vmbus_txbr *tbr)
297 {
298 	uint32_t rindex, windex;
299 
300 	/* Get snapshot */
301 	rindex = atomic_load_acq_32(&tbr->txbr_rindex);
302 	windex = atomic_load_acq_32(&tbr->txbr_windex);
303 
304 	return VMBUS_BR_WAVAIL(rindex, windex, tbr->txbr_dsize);
305 }
306 
307 static __inline uint32_t
308 vmbus_txbr_copyto(const struct vmbus_txbr *tbr, uint32_t windex,
309     const void *src0, uint32_t cplen)
310 {
311 	const uint8_t *src = src0;
312 	uint8_t *br_data = tbr->txbr_data;
313 	uint32_t br_dsize = tbr->txbr_dsize;
314 
315 	if (cplen > br_dsize - windex) {
316 		uint32_t fraglen = br_dsize - windex;
317 
318 		/* Wrap-around detected */
319 		memcpy(br_data + windex, src, fraglen);
320 		memcpy(br_data, src + fraglen, cplen - fraglen);
321 	} else {
322 		memcpy(br_data + windex, src, cplen);
323 	}
324 	return VMBUS_BR_IDXINC(windex, cplen, br_dsize);
325 }
326 
327 static __inline uint32_t
328 vmbus_txbr_copyto_call(const struct vmbus_txbr *tbr, uint32_t windex,
329     uint32_t cplen, vmbus_br_copy_callback_t cb, void *cbarg, int *ret)
330 {
331 	uint8_t *br_data = tbr->txbr_data;
332 	uint32_t br_dsize = tbr->txbr_dsize;
333 	int err = 0;
334 
335 	if (cplen > br_dsize - windex) {
336 		uint32_t fraglen = br_dsize - windex;
337 
338 		/* Wrap-around detected */
339 		err = cb((void *)(br_data + windex), fraglen, cbarg);
340 		if (!err)
341 			err = cb((void *)br_data, cplen - fraglen, cbarg);
342 	} else {
343 		err = cb((void *)(br_data + windex), cplen, cbarg);
344 	}
345 
346 	*ret = err;
347 
348 	return VMBUS_BR_IDXINC(windex, cplen, br_dsize);
349 }
350 
351 uint32_t
352 vmbus_txbr_available(const struct vmbus_txbr *tbr)
353 {
354 	return (vmbus_txbr_avail(tbr));
355 }
356 
357 /*
358  * NOTE:
359  * Not holding lock when calling user provided callback routine.
360  * Caller should hold lock to serialize ring buffer accesses.
361  */
362 int
363 vmbus_txbr_write_call(struct vmbus_txbr *tbr,
364     const struct iovec iov[], int iovlen,
365     vmbus_br_copy_callback_t cb, void *cbarg,
366     boolean_t *need_sig)
367 {
368 	uint32_t old_windex, windex, total;
369 	uint64_t save_windex;
370 	int i;
371 	int cb_ret = 0;
372 
373 	total = 0;
374 	for (i = 0; i < iovlen; i++)
375 		total += iov[i].iov_len;
376 	total += sizeof(save_windex);
377 
378 
379 	/*
380 	 * NOTE:
381 	 * If this write is going to make br_windex same as br_rindex,
382 	 * i.e. the available space for write is same as the write size,
383 	 * we can't do it then, since br_windex == br_rindex means that
384 	 * the bufring is empty.
385 	 */
386 	if (vmbus_txbr_avail(tbr) <= total) {
387 		return (EAGAIN);
388 	}
389 
390 	/* Save br_windex for later use */
391 	old_windex = tbr->txbr_windex;
392 
393 	/*
394 	 * Copy the scattered channel packet to the TX bufring.
395 	 */
396 	windex = old_windex;
397 	for (i = 0; i < iovlen; i++) {
398 		if (iov[i].iov_base != NULL) {
399 			windex = vmbus_txbr_copyto(tbr, windex,
400 			    iov[i].iov_base, iov[i].iov_len);
401 		} else if (cb != NULL) {
402 			windex = vmbus_txbr_copyto_call(tbr, windex,
403 			    iov[i].iov_len, cb, cbarg, &cb_ret);
404 			/*
405 			 * If callback fails, return without updating
406 			 * write index.
407 			 */
408 			if (cb_ret)
409 				return (cb_ret);
410 		}
411 	}
412 
413 	mtx_lock_spin(&tbr->txbr_lock);
414 
415 	/*
416 	 * Set the offset of the current channel packet.
417 	 */
418 	save_windex = ((uint64_t)old_windex) << 32;
419 	windex = vmbus_txbr_copyto(tbr, windex, &save_windex,
420 	    sizeof(save_windex));
421 
422 	/*
423 	 * Update the write index _after_ the channel packet
424 	 * is copied.
425 	 */
426 	__compiler_membar();
427 	atomic_store_rel_32(&tbr->txbr_windex, windex);
428 
429 	mtx_unlock_spin(&tbr->txbr_lock);
430 
431 	if (need_sig)
432 		*need_sig = vmbus_txbr_need_signal(tbr, old_windex);
433 
434 	return (0);
435 }
436 
437 /*
438  * Write scattered channel packet to TX bufring.
439  *
440  * The offset of this channel packet is written as a 64bits value
441  * immediately after this channel packet.
442  */
443 int
444 vmbus_txbr_write(struct vmbus_txbr *tbr, const struct iovec iov[], int iovlen,
445     boolean_t *need_sig)
446 {
447 	uint32_t old_windex, windex, total;
448 	uint64_t save_windex;
449 	int i;
450 
451 	total = 0;
452 	for (i = 0; i < iovlen; i++)
453 		total += iov[i].iov_len;
454 	total += sizeof(save_windex);
455 
456 	mtx_lock_spin(&tbr->txbr_lock);
457 
458 	/*
459 	 * NOTE:
460 	 * If this write is going to make br_windex same as br_rindex,
461 	 * i.e. the available space for write is same as the write size,
462 	 * we can't do it then, since br_windex == br_rindex means that
463 	 * the bufring is empty.
464 	 */
465 	if (vmbus_txbr_avail(tbr) <= total) {
466 		mtx_unlock_spin(&tbr->txbr_lock);
467 		return (EAGAIN);
468 	}
469 
470 	/* Save br_windex for later use */
471 	old_windex = atomic_load_acq_32(&tbr->txbr_windex);
472 
473 	/*
474 	 * Copy the scattered channel packet to the TX bufring.
475 	 */
476 	windex = old_windex;
477 	for (i = 0; i < iovlen; i++) {
478 		windex = vmbus_txbr_copyto(tbr, windex,
479 		    iov[i].iov_base, iov[i].iov_len);
480 	}
481 
482 	/*
483 	 * Set the offset of the current channel packet.
484 	 */
485 	save_windex = ((uint64_t)old_windex) << 32;
486 	windex = vmbus_txbr_copyto(tbr, windex, &save_windex,
487 	    sizeof(save_windex));
488 
489 	/*
490 	 * Update the write index _after_ the channel packet
491 	 * is copied.
492 	 */
493 	__compiler_membar();
494 	atomic_store_rel_32(&tbr->txbr_windex, windex);
495 
496 	mtx_unlock_spin(&tbr->txbr_lock);
497 
498 	*need_sig = vmbus_txbr_need_signal(tbr, old_windex);
499 
500 	return (0);
501 }
502 
503 static __inline uint32_t
504 vmbus_rxbr_copyfrom(const struct vmbus_rxbr *rbr, uint32_t rindex,
505     void *dst0, int cplen)
506 {
507 	uint8_t *dst = dst0;
508 	const uint8_t *br_data = rbr->rxbr_data;
509 	uint32_t br_dsize = rbr->rxbr_dsize;
510 
511 	if (cplen > br_dsize - rindex) {
512 		uint32_t fraglen = br_dsize - rindex;
513 
514 		/* Wrap-around detected. */
515 		memcpy(dst, br_data + rindex, fraglen);
516 		memcpy(dst + fraglen, br_data, cplen - fraglen);
517 	} else {
518 		memcpy(dst, br_data + rindex, cplen);
519 	}
520 	return VMBUS_BR_IDXINC(rindex, cplen, br_dsize);
521 }
522 
523 static __inline uint32_t
524 vmbus_rxbr_copyfrom_call(const struct vmbus_rxbr *rbr, uint32_t rindex,
525     int cplen, vmbus_br_copy_callback_t cb, void *cbarg)
526 {
527 	uint8_t *br_data = rbr->rxbr_data;
528 	uint32_t br_dsize = rbr->rxbr_dsize;
529 	int error = 0;
530 
531 	if (cplen > br_dsize - rindex) {
532 		uint32_t fraglen = br_dsize - rindex;
533 
534 		/* Wrap-around detected. */
535 		error = cb((void *)(br_data + rindex), fraglen, cbarg);
536 		if (!error)
537 			error = cb((void *)br_data, cplen - fraglen, cbarg);
538 	} else {
539 		error = cb((void *)(br_data + rindex), cplen, cbarg);
540 	}
541 	return (error);
542 }
543 
544 int
545 vmbus_rxbr_peek(struct vmbus_rxbr *rbr, void *data, int dlen)
546 {
547 	mtx_lock_spin(&rbr->rxbr_lock);
548 
549 	/*
550 	 * The requested data and the 64bits channel packet
551 	 * offset should be there at least.
552 	 */
553 	if (vmbus_rxbr_avail(rbr) < dlen + sizeof(uint64_t)) {
554 		mtx_unlock_spin(&rbr->rxbr_lock);
555 		return (EAGAIN);
556 	}
557 	vmbus_rxbr_copyfrom(rbr,
558 	    atomic_load_acq_32(&rbr->rxbr_rindex), data, dlen);
559 
560 	mtx_unlock_spin(&rbr->rxbr_lock);
561 
562 	return (0);
563 }
564 
565 /*
566  * NOTE:
567  * We only hold spin lock to check the ring buffer space. It is
568  * released before calling user provided callback routine.
569  * Caller should hold lock to serialize ring buffer accesses.
570  */
571 int
572 vmbus_rxbr_peek_call(struct vmbus_rxbr *rbr, int dlen, uint32_t skip,
573     vmbus_br_copy_callback_t cb, void *cbarg)
574 {
575 	uint32_t rindex, br_dsize0 = rbr->rxbr_dsize;
576 	int ret;
577 
578 	mtx_lock_spin(&rbr->rxbr_lock);
579 	/*
580 	 * The requested data + skip and the 64bits channel packet
581 	 * offset should be there at least.
582 	 */
583 	if (vmbus_rxbr_avail(rbr) < skip + dlen + sizeof(uint64_t)) {
584 		mtx_unlock_spin(&rbr->rxbr_lock);
585 		return (EAGAIN);
586 	}
587 
588 	rindex = VMBUS_BR_IDXINC(rbr->rxbr_rindex, skip, br_dsize0);
589 	mtx_unlock_spin(&rbr->rxbr_lock);
590 
591 	ret = vmbus_rxbr_copyfrom_call(rbr, rindex, dlen, cb, cbarg);
592 
593 	return (ret);
594 }
595 
596 /*
597  * NOTE:
598  * We assume idx_adv == sizeof(channel packet).
599  */
600 int
601 vmbus_rxbr_idxadv_peek(struct vmbus_rxbr *rbr, void *data, int dlen,
602     uint32_t idx_adv, boolean_t *need_sig)
603 {
604 	uint32_t rindex, br_dsize = rbr->rxbr_dsize;
605 
606 	mtx_lock_spin(&rbr->rxbr_lock);
607 	/*
608 	 * Make sure it has enough data to read.
609 	 */
610 	if (vmbus_rxbr_avail(rbr) < idx_adv + sizeof(uint64_t) + dlen) {
611 		mtx_unlock_spin(&rbr->rxbr_lock);
612 		return (EAGAIN);
613 	}
614 
615 	if (idx_adv > 0) {
616 		/*
617 		 * Advance the read index first, including the channel's 64bit
618 		 * previous write offset.
619 		 */
620 		rindex = VMBUS_BR_IDXINC(rbr->rxbr_rindex,
621 		    idx_adv + sizeof(uint64_t), br_dsize);
622 		__compiler_membar();
623 		atomic_store_rel_32(&rbr->rxbr_rindex, rindex);
624 	}
625 
626 	vmbus_rxbr_copyfrom(rbr,
627 	    atomic_load_acq_32(&rbr->rxbr_rindex), data, dlen);
628 
629 	mtx_unlock_spin(&rbr->rxbr_lock);
630 
631 	if (need_sig) {
632 		if (idx_adv > 0)
633 			*need_sig =
634 			    vmbus_rxbr_need_signal(rbr, idx_adv +
635 			    sizeof(uint64_t));
636 		else
637 			*need_sig = false;
638 	}
639 
640 	return (0);
641 }
642 
643 /*
644  * NOTE:
645  * Just update the RX rb index.
646  */
647 int
648 vmbus_rxbr_idxadv(struct vmbus_rxbr *rbr, uint32_t idx_adv,
649     boolean_t *need_sig)
650 {
651 	uint32_t rindex, br_dsize = rbr->rxbr_dsize;
652 
653 	mtx_lock_spin(&rbr->rxbr_lock);
654 	/*
655 	 * Make sure it has enough space to advance.
656 	 */
657 	if (vmbus_rxbr_avail(rbr) < idx_adv + sizeof(uint64_t)) {
658 		mtx_unlock_spin(&rbr->rxbr_lock);
659 		return (EAGAIN);
660 	}
661 
662 	/*
663 	 * Advance the read index, including the channel's 64bit
664 	 * previous write offset.
665 	 */
666 	rindex = VMBUS_BR_IDXINC(rbr->rxbr_rindex,
667 	    idx_adv + sizeof(uint64_t), br_dsize);
668 	__compiler_membar();
669 	atomic_store_rel_32(&rbr->rxbr_rindex, rindex);
670 
671 	mtx_unlock_spin(&rbr->rxbr_lock);
672 
673 	if (need_sig) {
674 		*need_sig =
675 		    vmbus_rxbr_need_signal(rbr, idx_adv + sizeof(uint64_t));
676 	}
677 
678 	return (0);
679 }
680 
681 /*
682  * NOTE:
683  * We assume (dlen + skip) == sizeof(channel packet).
684  */
685 int
686 vmbus_rxbr_read(struct vmbus_rxbr *rbr, void *data, int dlen, uint32_t skip,
687     boolean_t *need_sig)
688 {
689 	uint32_t rindex, br_dsize = rbr->rxbr_dsize;
690 
691 	KASSERT(dlen + skip > 0, ("invalid dlen %d, offset %u", dlen, skip));
692 
693 	mtx_lock_spin(&rbr->rxbr_lock);
694 
695 	if (vmbus_rxbr_avail(rbr) < dlen + skip + sizeof(uint64_t)) {
696 		mtx_unlock_spin(&rbr->rxbr_lock);
697 		return (EAGAIN);
698 	}
699 
700 	/*
701 	 * Copy channel packet from RX bufring.
702 	 */
703 	rindex = VMBUS_BR_IDXINC(atomic_load_acq_32(&rbr->rxbr_rindex),
704 	    skip, br_dsize);
705 	rindex = vmbus_rxbr_copyfrom(rbr, rindex, data, dlen);
706 
707 	/*
708 	 * Discard this channel packet's 64bits offset, which is useless to us.
709 	 */
710 	rindex = VMBUS_BR_IDXINC(rindex, sizeof(uint64_t), br_dsize);
711 
712 	/*
713 	 * Update the read index _after_ the channel packet is fetched.
714 	 */
715 	__compiler_membar();
716 	atomic_store_rel_32(&rbr->rxbr_rindex, rindex);
717 
718 	mtx_unlock_spin(&rbr->rxbr_lock);
719 
720 	if (need_sig) {
721 		*need_sig =
722 		    vmbus_rxbr_need_signal(rbr,
723 		    dlen + skip + sizeof(uint64_t));
724 	}
725 
726 	return (0);
727 }
728