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