The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/hyperv/vmbus/vmbus_br.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 93099a9055b14a3825e4323c18415b97


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.