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_xact.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) 2016 Microsoft Corp.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/lock.h>
   32 #include <sys/malloc.h>
   33 #include <sys/mutex.h>
   34 #include <sys/proc.h>
   35 #include <sys/systm.h>
   36 
   37 #include <dev/hyperv/include/hyperv_busdma.h>
   38 #include <dev/hyperv/include/vmbus_xact.h>
   39 
   40 struct vmbus_xact {
   41         struct vmbus_xact_ctx           *x_ctx;
   42         void                            *x_priv;
   43 
   44         void                            *x_req;
   45         struct hyperv_dma               x_req_dma;
   46 
   47         const void                      *x_resp;
   48         size_t                          x_resp_len;
   49         void                            *x_resp0;
   50 };
   51 
   52 struct vmbus_xact_ctx {
   53         size_t                          xc_req_size;
   54         size_t                          xc_resp_size;
   55         size_t                          xc_priv_size;
   56 
   57         struct mtx                      xc_lock;
   58         /*
   59          * Protected by xc_lock.
   60          */
   61         uint32_t                        xc_flags;       /* VMBUS_XACT_CTXF_ */
   62         struct vmbus_xact               *xc_free;
   63         struct vmbus_xact               *xc_active;
   64         struct vmbus_xact               *xc_orphan;
   65 };
   66 
   67 #define VMBUS_XACT_CTXF_DESTROY         0x0001
   68 
   69 static struct vmbus_xact        *vmbus_xact_alloc(struct vmbus_xact_ctx *,
   70                                     bus_dma_tag_t);
   71 static void                     vmbus_xact_free(struct vmbus_xact *);
   72 static struct vmbus_xact        *vmbus_xact_get1(struct vmbus_xact_ctx *,
   73                                     uint32_t);
   74 static const void               *vmbus_xact_wait1(struct vmbus_xact *, size_t *,
   75                                     bool);
   76 static const void               *vmbus_xact_return(struct vmbus_xact *,
   77                                     size_t *);
   78 static void                     vmbus_xact_save_resp(struct vmbus_xact *,
   79                                     const void *, size_t);
   80 static void                     vmbus_xact_ctx_free(struct vmbus_xact_ctx *);
   81 
   82 static struct vmbus_xact *
   83 vmbus_xact_alloc(struct vmbus_xact_ctx *ctx, bus_dma_tag_t parent_dtag)
   84 {
   85         struct vmbus_xact *xact;
   86 
   87         xact = malloc(sizeof(*xact), M_DEVBUF, M_WAITOK | M_ZERO);
   88         xact->x_ctx = ctx;
   89 
   90         /* XXX assume that page aligned is enough */
   91         xact->x_req = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
   92             ctx->xc_req_size, &xact->x_req_dma, BUS_DMA_WAITOK);
   93         if (xact->x_req == NULL) {
   94                 free(xact, M_DEVBUF);
   95                 return (NULL);
   96         }
   97         if (ctx->xc_priv_size != 0)
   98                 xact->x_priv = malloc(ctx->xc_priv_size, M_DEVBUF, M_WAITOK);
   99         xact->x_resp0 = malloc(ctx->xc_resp_size, M_DEVBUF, M_WAITOK);
  100 
  101         return (xact);
  102 }
  103 
  104 static void
  105 vmbus_xact_free(struct vmbus_xact *xact)
  106 {
  107 
  108         hyperv_dmamem_free(&xact->x_req_dma, xact->x_req);
  109         free(xact->x_resp0, M_DEVBUF);
  110         if (xact->x_priv != NULL)
  111                 free(xact->x_priv, M_DEVBUF);
  112         free(xact, M_DEVBUF);
  113 }
  114 
  115 static struct vmbus_xact *
  116 vmbus_xact_get1(struct vmbus_xact_ctx *ctx, uint32_t dtor_flag)
  117 {
  118         struct vmbus_xact *xact;
  119 
  120         mtx_lock(&ctx->xc_lock);
  121 
  122         while ((ctx->xc_flags & dtor_flag) == 0 && ctx->xc_free == NULL)
  123                 mtx_sleep(&ctx->xc_free, &ctx->xc_lock, 0, "gxact", 0);
  124         if (ctx->xc_flags & dtor_flag) {
  125                 /* Being destroyed */
  126                 xact = NULL;
  127         } else {
  128                 xact = ctx->xc_free;
  129                 KASSERT(xact != NULL, ("no free xact"));
  130                 KASSERT(xact->x_resp == NULL, ("xact has pending response"));
  131                 ctx->xc_free = NULL;
  132         }
  133 
  134         mtx_unlock(&ctx->xc_lock);
  135 
  136         return (xact);
  137 }
  138 
  139 struct vmbus_xact_ctx *
  140 vmbus_xact_ctx_create(bus_dma_tag_t dtag, size_t req_size, size_t resp_size,
  141     size_t priv_size)
  142 {
  143         struct vmbus_xact_ctx *ctx;
  144 
  145         KASSERT(req_size > 0, ("request size is 0"));
  146         KASSERT(resp_size > 0, ("response size is 0"));
  147 
  148         ctx = malloc(sizeof(*ctx), M_DEVBUF, M_WAITOK | M_ZERO);
  149         ctx->xc_req_size = req_size;
  150         ctx->xc_resp_size = resp_size;
  151         ctx->xc_priv_size = priv_size;
  152 
  153         ctx->xc_free = vmbus_xact_alloc(ctx, dtag);
  154         if (ctx->xc_free == NULL) {
  155                 free(ctx, M_DEVBUF);
  156                 return (NULL);
  157         }
  158 
  159         mtx_init(&ctx->xc_lock, "vmbus xact", NULL, MTX_DEF);
  160 
  161         return (ctx);
  162 }
  163 
  164 bool
  165 vmbus_xact_ctx_orphan(struct vmbus_xact_ctx *ctx)
  166 {
  167         mtx_lock(&ctx->xc_lock);
  168         if (ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY) {
  169                 mtx_unlock(&ctx->xc_lock);
  170                 return (false);
  171         }
  172         ctx->xc_flags |= VMBUS_XACT_CTXF_DESTROY;
  173         mtx_unlock(&ctx->xc_lock);
  174 
  175         wakeup(&ctx->xc_free);
  176         wakeup(&ctx->xc_active);
  177 
  178         ctx->xc_orphan = vmbus_xact_get1(ctx, 0);
  179         if (ctx->xc_orphan == NULL)
  180                 panic("can't get xact");
  181         return (true);
  182 }
  183 
  184 static void
  185 vmbus_xact_ctx_free(struct vmbus_xact_ctx *ctx)
  186 {
  187         KASSERT(ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY,
  188             ("xact ctx was not orphaned"));
  189         KASSERT(ctx->xc_orphan != NULL, ("no orphaned xact"));
  190 
  191         vmbus_xact_free(ctx->xc_orphan);
  192         mtx_destroy(&ctx->xc_lock);
  193         free(ctx, M_DEVBUF);
  194 }
  195 
  196 void
  197 vmbus_xact_ctx_destroy(struct vmbus_xact_ctx *ctx)
  198 {
  199 
  200         vmbus_xact_ctx_orphan(ctx);
  201         vmbus_xact_ctx_free(ctx);
  202 }
  203 
  204 struct vmbus_xact *
  205 vmbus_xact_get(struct vmbus_xact_ctx *ctx, size_t req_len)
  206 {
  207         struct vmbus_xact *xact;
  208 
  209         if (req_len > ctx->xc_req_size)
  210                 panic("invalid request size %zu", req_len);
  211 
  212         xact = vmbus_xact_get1(ctx, VMBUS_XACT_CTXF_DESTROY);
  213         if (xact == NULL)
  214                 return (NULL);
  215 
  216         memset(xact->x_req, 0, req_len);
  217         return (xact);
  218 }
  219 
  220 void
  221 vmbus_xact_put(struct vmbus_xact *xact)
  222 {
  223         struct vmbus_xact_ctx *ctx = xact->x_ctx;
  224 
  225         KASSERT(ctx->xc_active == NULL, ("pending active xact"));
  226         xact->x_resp = NULL;
  227 
  228         mtx_lock(&ctx->xc_lock);
  229         KASSERT(ctx->xc_free == NULL, ("has free xact"));
  230         ctx->xc_free = xact;
  231         mtx_unlock(&ctx->xc_lock);
  232         wakeup(&ctx->xc_free);
  233 }
  234 
  235 void *
  236 vmbus_xact_req_data(const struct vmbus_xact *xact)
  237 {
  238 
  239         return (xact->x_req);
  240 }
  241 
  242 bus_addr_t
  243 vmbus_xact_req_paddr(const struct vmbus_xact *xact)
  244 {
  245 
  246         return (xact->x_req_dma.hv_paddr);
  247 }
  248 
  249 void *
  250 vmbus_xact_priv(const struct vmbus_xact *xact, size_t priv_len)
  251 {
  252 
  253         if (priv_len > xact->x_ctx->xc_priv_size)
  254                 panic("invalid priv size %zu", priv_len);
  255         return (xact->x_priv);
  256 }
  257 
  258 void
  259 vmbus_xact_activate(struct vmbus_xact *xact)
  260 {
  261         struct vmbus_xact_ctx *ctx = xact->x_ctx;
  262 
  263         KASSERT(xact->x_resp == NULL, ("xact has pending response"));
  264 
  265         mtx_lock(&ctx->xc_lock);
  266         KASSERT(ctx->xc_active == NULL, ("pending active xact"));
  267         ctx->xc_active = xact;
  268         mtx_unlock(&ctx->xc_lock);
  269 }
  270 
  271 void
  272 vmbus_xact_deactivate(struct vmbus_xact *xact)
  273 {
  274         struct vmbus_xact_ctx *ctx = xact->x_ctx;
  275 
  276         mtx_lock(&ctx->xc_lock);
  277         KASSERT(ctx->xc_active == xact, ("xact mismatch"));
  278         ctx->xc_active = NULL;
  279         mtx_unlock(&ctx->xc_lock);
  280 }
  281 
  282 static const void *
  283 vmbus_xact_return(struct vmbus_xact *xact, size_t *resp_len)
  284 {
  285         struct vmbus_xact_ctx *ctx = xact->x_ctx;
  286         const void *resp;
  287 
  288         mtx_assert(&ctx->xc_lock, MA_OWNED);
  289         KASSERT(ctx->xc_active == xact, ("xact trashed"));
  290 
  291         if ((ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY) && xact->x_resp == NULL) {
  292                 uint8_t b = 0;
  293 
  294                 /*
  295                  * Orphaned and no response was received yet; fake up
  296                  * an one byte response.
  297                  */
  298                 printf("vmbus: xact ctx was orphaned w/ pending xact\n");
  299                 vmbus_xact_save_resp(ctx->xc_active, &b, sizeof(b));
  300         }
  301         KASSERT(xact->x_resp != NULL, ("no response"));
  302 
  303         ctx->xc_active = NULL;
  304 
  305         resp = xact->x_resp;
  306         *resp_len = xact->x_resp_len;
  307 
  308         return (resp);
  309 }
  310 
  311 static const void *
  312 vmbus_xact_wait1(struct vmbus_xact *xact, size_t *resp_len,
  313     bool can_sleep)
  314 {
  315         struct vmbus_xact_ctx *ctx = xact->x_ctx;
  316         const void *resp;
  317 
  318         mtx_lock(&ctx->xc_lock);
  319 
  320         KASSERT(ctx->xc_active == xact, ("xact mismatch"));
  321         while (xact->x_resp == NULL &&
  322             (ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY) == 0) {
  323                 if (can_sleep) {
  324                         mtx_sleep(&ctx->xc_active, &ctx->xc_lock, 0,
  325                             "wxact", 0);
  326                 } else {
  327                         mtx_unlock(&ctx->xc_lock);
  328                         DELAY(1000);
  329                         mtx_lock(&ctx->xc_lock);
  330                 }
  331         }
  332         resp = vmbus_xact_return(xact, resp_len);
  333 
  334         mtx_unlock(&ctx->xc_lock);
  335 
  336         return (resp);
  337 }
  338 
  339 const void *
  340 vmbus_xact_wait(struct vmbus_xact *xact, size_t *resp_len)
  341 {
  342 
  343         return (vmbus_xact_wait1(xact, resp_len, true /* can sleep */));
  344 }
  345 
  346 const void *
  347 vmbus_xact_busywait(struct vmbus_xact *xact, size_t *resp_len)
  348 {
  349 
  350         return (vmbus_xact_wait1(xact, resp_len, false /* can't sleep */));
  351 }
  352 
  353 const void *
  354 vmbus_xact_poll(struct vmbus_xact *xact, size_t *resp_len)
  355 {
  356         struct vmbus_xact_ctx *ctx = xact->x_ctx;
  357         const void *resp;
  358 
  359         mtx_lock(&ctx->xc_lock);
  360 
  361         KASSERT(ctx->xc_active == xact, ("xact mismatch"));
  362         if (xact->x_resp == NULL &&
  363             (ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY) == 0) {
  364                 mtx_unlock(&ctx->xc_lock);
  365                 *resp_len = 0;
  366                 return (NULL);
  367         }
  368         resp = vmbus_xact_return(xact, resp_len);
  369 
  370         mtx_unlock(&ctx->xc_lock);
  371 
  372         return (resp);
  373 }
  374 
  375 static void
  376 vmbus_xact_save_resp(struct vmbus_xact *xact, const void *data, size_t dlen)
  377 {
  378         struct vmbus_xact_ctx *ctx = xact->x_ctx;
  379         size_t cplen = dlen;
  380 
  381         mtx_assert(&ctx->xc_lock, MA_OWNED);
  382 
  383         if (cplen > ctx->xc_resp_size) {
  384                 printf("vmbus: xact response truncated %zu -> %zu\n",
  385                     cplen, ctx->xc_resp_size);
  386                 cplen = ctx->xc_resp_size;
  387         }
  388 
  389         KASSERT(ctx->xc_active == xact, ("xact mismatch"));
  390         memcpy(xact->x_resp0, data, cplen);
  391         xact->x_resp_len = cplen;
  392         xact->x_resp = xact->x_resp0;
  393 }
  394 
  395 void
  396 vmbus_xact_wakeup(struct vmbus_xact *xact, const void *data, size_t dlen)
  397 {
  398         struct vmbus_xact_ctx *ctx = xact->x_ctx;
  399         int do_wakeup = 0;
  400 
  401         mtx_lock(&ctx->xc_lock);
  402         /*
  403          * NOTE:
  404          * xc_active could be NULL, if the ctx has been orphaned.
  405          */
  406         if (ctx->xc_active != NULL) {
  407                 vmbus_xact_save_resp(xact, data, dlen);
  408                 do_wakeup = 1;
  409         } else {
  410                 KASSERT(ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY,
  411                     ("no active xact pending"));
  412                 printf("vmbus: drop xact response\n");
  413         }
  414         mtx_unlock(&ctx->xc_lock);
  415 
  416         if (do_wakeup)
  417                 wakeup(&ctx->xc_active);
  418 }
  419 
  420 void
  421 vmbus_xact_ctx_wakeup(struct vmbus_xact_ctx *ctx, const void *data, size_t dlen)
  422 {
  423         int do_wakeup = 0;
  424 
  425         mtx_lock(&ctx->xc_lock);
  426         /*
  427          * NOTE:
  428          * xc_active could be NULL, if the ctx has been orphaned.
  429          */
  430         if (ctx->xc_active != NULL) {
  431                 vmbus_xact_save_resp(ctx->xc_active, data, dlen);
  432                 do_wakeup = 1;
  433         } else {
  434                 KASSERT(ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY,
  435                     ("no active xact pending"));
  436                 printf("vmbus: drop xact response\n");
  437         }
  438         mtx_unlock(&ctx->xc_lock);
  439 
  440         if (do_wakeup)
  441                 wakeup(&ctx->xc_active);
  442 }

Cache object: 511cafb3b16e43a570fa8f5e9a585e11


[ 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.