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
vmbus_br_sysctl_state(SYSCTL_HANDLER_ARGS)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
vmbus_br_sysctl_state_bin(SYSCTL_HANDLER_ARGS)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
vmbus_br_sysctl_create(struct sysctl_ctx_list * ctx,struct sysctl_oid * br_tree,struct vmbus_br * br,const char * name)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
vmbus_rxbr_intr_mask(struct vmbus_rxbr * rbr)130 vmbus_rxbr_intr_mask(struct vmbus_rxbr *rbr)
131 {
132 rbr->rxbr_imask = 1;
133 mb();
134 }
135
136 static __inline uint32_t
vmbus_rxbr_avail(const struct vmbus_rxbr * rbr)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
vmbus_rxbr_available(const struct vmbus_rxbr * rbr)150 vmbus_rxbr_available(const struct vmbus_rxbr *rbr)
151 {
152 return (vmbus_rxbr_avail(rbr));
153 }
154
155 uint32_t
vmbus_rxbr_intr_unmask(struct vmbus_rxbr * rbr)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
vmbus_br_setup(struct vmbus_br * br,void * buf,int blen)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
vmbus_rxbr_init(struct vmbus_rxbr * rbr)177 vmbus_rxbr_init(struct vmbus_rxbr *rbr)
178 {
179 mtx_init(&rbr->rxbr_lock, "vmbus_rxbr", NULL, MTX_SPIN);
180 }
181
182 void
vmbus_rxbr_deinit(struct vmbus_rxbr * rbr)183 vmbus_rxbr_deinit(struct vmbus_rxbr *rbr)
184 {
185 mtx_destroy(&rbr->rxbr_lock);
186 }
187
188 void
vmbus_rxbr_setup(struct vmbus_rxbr * rbr,void * buf,int blen)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
vmbus_rxbr_need_signal(const struct vmbus_rxbr * rbr,uint32_t bytes_read)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
vmbus_txbr_init(struct vmbus_txbr * tbr)229 vmbus_txbr_init(struct vmbus_txbr *tbr)
230 {
231 mtx_init(&tbr->txbr_lock, "vmbus_txbr", NULL, MTX_SPIN);
232 }
233
234 void
vmbus_txbr_deinit(struct vmbus_txbr * tbr)235 vmbus_txbr_deinit(struct vmbus_txbr *tbr)
236 {
237 mtx_destroy(&tbr->txbr_lock);
238 }
239
240 void
vmbus_txbr_setup(struct vmbus_txbr * tbr,void * buf,int blen)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
vmbus_txbr_get_imask(const struct vmbus_txbr * tbr)250 vmbus_txbr_get_imask(const struct vmbus_txbr *tbr)
251 {
252 mb();
253
254 return(tbr->txbr_imask);
255 }
256
257 void
vmbus_txbr_set_pending_snd_sz(struct vmbus_txbr * tbr,uint32_t size)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
vmbus_txbr_need_signal(const struct vmbus_txbr * tbr,uint32_t old_windex)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
vmbus_txbr_avail(const struct vmbus_txbr * tbr)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
vmbus_txbr_copyto(const struct vmbus_txbr * tbr,uint32_t windex,const void * src0,uint32_t cplen)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
vmbus_txbr_copyto_call(const struct vmbus_txbr * tbr,uint32_t windex,uint32_t cplen,vmbus_br_copy_callback_t cb,void * cbarg,int * ret)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
vmbus_txbr_available(const struct vmbus_txbr * tbr)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
vmbus_txbr_write_call(struct vmbus_txbr * tbr,const struct iovec iov[],int iovlen,vmbus_br_copy_callback_t cb,void * cbarg,boolean_t * need_sig)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
vmbus_txbr_write(struct vmbus_txbr * tbr,const struct iovec iov[],int iovlen,boolean_t * need_sig)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
vmbus_rxbr_copyfrom(const struct vmbus_rxbr * rbr,uint32_t rindex,void * dst0,int cplen)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
vmbus_rxbr_copyfrom_call(const struct vmbus_rxbr * rbr,uint32_t rindex,int cplen,vmbus_br_copy_callback_t cb,void * cbarg)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
vmbus_rxbr_peek(struct vmbus_rxbr * rbr,void * data,int dlen)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
vmbus_rxbr_peek_call(struct vmbus_rxbr * rbr,int dlen,uint32_t skip,vmbus_br_copy_callback_t cb,void * cbarg)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
vmbus_rxbr_idxadv_peek(struct vmbus_rxbr * rbr,void * data,int dlen,uint32_t idx_adv,boolean_t * need_sig)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
vmbus_rxbr_idxadv(struct vmbus_rxbr * rbr,uint32_t idx_adv,boolean_t * need_sig)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
vmbus_rxbr_read(struct vmbus_rxbr * rbr,void * data,int dlen,uint32_t skip,boolean_t * need_sig)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