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/utilities/vmbus_timesync.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) 2014,2016-2017 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/bus.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/syscallsubr.h>
   35 #include <sys/sysctl.h>
   36 #include <sys/systm.h>
   37 
   38 #include <dev/hyperv/include/hyperv.h>
   39 #include <dev/hyperv/include/vmbus.h>
   40 #include <dev/hyperv/utilities/vmbus_icreg.h>
   41 #include <dev/hyperv/utilities/vmbus_icvar.h>
   42 
   43 #define VMBUS_TIMESYNC_FWVER_MAJOR      3
   44 #define VMBUS_TIMESYNC_FWVER            \
   45         VMBUS_IC_VERSION(VMBUS_TIMESYNC_FWVER_MAJOR, 0)
   46 
   47 #define VMBUS_TIMESYNC_MSGVER_MAJOR     4
   48 #define VMBUS_TIMESYNC_MSGVER           \
   49         VMBUS_IC_VERSION(VMBUS_TIMESYNC_MSGVER_MAJOR, 0)
   50 
   51 #define VMBUS_TIMESYNC_MSGVER4(sc)      \
   52         VMBUS_ICVER_LE(VMBUS_IC_VERSION(4, 0), (sc)->ic_msgver)
   53 
   54 #define VMBUS_TIMESYNC_DORTT(sc)        \
   55         (VMBUS_TIMESYNC_MSGVER4((sc)) && hyperv_tc64 != NULL)
   56 
   57 static int                      vmbus_timesync_probe(device_t);
   58 static int                      vmbus_timesync_attach(device_t);
   59 
   60 static const struct vmbus_ic_desc vmbus_timesync_descs[] = {
   61         {
   62                 .ic_guid = { .hv_guid = {
   63                     0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
   64                     0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf } },
   65                 .ic_desc = "Hyper-V Timesync"
   66         },
   67         VMBUS_IC_DESC_END
   68 };
   69 
   70 static device_method_t vmbus_timesync_methods[] = {
   71         /* Device interface */
   72         DEVMETHOD(device_probe,         vmbus_timesync_probe),
   73         DEVMETHOD(device_attach,        vmbus_timesync_attach),
   74         DEVMETHOD(device_detach,        vmbus_ic_detach),
   75         DEVMETHOD_END
   76 };
   77 
   78 static driver_t vmbus_timesync_driver = {
   79         "hvtimesync",
   80         vmbus_timesync_methods,
   81         sizeof(struct vmbus_ic_softc)
   82 };
   83 
   84 DRIVER_MODULE(hv_timesync, vmbus, vmbus_timesync_driver, NULL, NULL);
   85 MODULE_VERSION(hv_timesync, 1);
   86 MODULE_DEPEND(hv_timesync, vmbus, 1, 1, 1);
   87 
   88 SYSCTL_NODE(_hw, OID_AUTO, hvtimesync, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
   89     "Hyper-V timesync interface");
   90 
   91 static int vmbus_ts_ignore_sync = 0;
   92 SYSCTL_INT(_hw_hvtimesync, OID_AUTO, ignore_sync, CTLFLAG_RWTUN,
   93     &vmbus_ts_ignore_sync, 0, "Ignore the sync request.");
   94 
   95 /*
   96  * Trigger sample sync when drift exceeds threshold (ms).
   97  * Ignore the sample request when set to 0.
   98  */
   99 static int vmbus_ts_sample_thresh = 100;
  100 SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_thresh, CTLFLAG_RWTUN,
  101     &vmbus_ts_sample_thresh, 0,
  102     "Threshold that makes sample request trigger the sync (unit: ms).");
  103 
  104 static int vmbus_ts_sample_verbose = 0;
  105 SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_verbose, CTLFLAG_RWTUN,
  106     &vmbus_ts_sample_verbose, 0, "Increase sample request verbosity.");
  107 
  108 static void
  109 vmbus_timesync(struct vmbus_ic_softc *sc, uint64_t hvtime, uint64_t sent_tc,
  110     uint8_t tsflags)
  111 {
  112         struct timespec vm_ts;
  113         uint64_t hv_ns, vm_ns, rtt = 0;
  114 
  115         if (VMBUS_TIMESYNC_DORTT(sc))
  116                 rtt = hyperv_tc64() - sent_tc;
  117 
  118         hv_ns = (hvtime - VMBUS_ICMSG_TS_BASE + rtt) * HYPERV_TIMER_NS_FACTOR;
  119         nanotime(&vm_ts);
  120         vm_ns = (vm_ts.tv_sec * NANOSEC) + vm_ts.tv_nsec;
  121 
  122         if ((tsflags & VMBUS_ICMSG_TS_FLAG_SYNC) && !vmbus_ts_ignore_sync) {
  123                 struct timespec hv_ts;
  124 
  125                 if (bootverbose) {
  126                         device_printf(sc->ic_dev, "apply sync request, "
  127                             "hv: %ju, vm: %ju\n",
  128                             (uintmax_t)hv_ns, (uintmax_t)vm_ns);
  129                 }
  130                 hv_ts.tv_sec = hv_ns / NANOSEC;
  131                 hv_ts.tv_nsec = hv_ns % NANOSEC;
  132                 kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts);
  133                 /* Done! */
  134                 return;
  135         }
  136 
  137         if ((tsflags & VMBUS_ICMSG_TS_FLAG_SAMPLE) &&
  138             vmbus_ts_sample_thresh >= 0) {
  139                 int64_t diff;
  140 
  141                 if (vmbus_ts_sample_verbose) {
  142                         device_printf(sc->ic_dev, "sample request, "
  143                             "hv: %ju, vm: %ju\n",
  144                             (uintmax_t)hv_ns, (uintmax_t)vm_ns);
  145                 }
  146 
  147                 if (hv_ns > vm_ns)
  148                         diff = hv_ns - vm_ns;
  149                 else
  150                         diff = vm_ns - hv_ns;
  151                 /* nanosec -> millisec */
  152                 diff /= 1000000;
  153 
  154                 if (diff > vmbus_ts_sample_thresh) {
  155                         struct timespec hv_ts;
  156 
  157                         if (bootverbose) {
  158                                 device_printf(sc->ic_dev,
  159                                     "apply sample request, hv: %ju, vm: %ju\n",
  160                                     (uintmax_t)hv_ns, (uintmax_t)vm_ns);
  161                         }
  162                         hv_ts.tv_sec = hv_ns / NANOSEC;
  163                         hv_ts.tv_nsec = hv_ns % NANOSEC;
  164                         kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts);
  165                 }
  166                 /* Done */
  167                 return;
  168         }
  169 }
  170 
  171 static void
  172 vmbus_timesync_cb(struct vmbus_channel *chan, void *xsc)
  173 {
  174         struct vmbus_ic_softc *sc = xsc;
  175         struct vmbus_icmsg_hdr *hdr;
  176         int dlen, error;
  177         uint64_t xactid;
  178         void *data;
  179 
  180         /*
  181          * Receive request.
  182          */
  183         data = sc->ic_buf;
  184         dlen = sc->ic_buflen;
  185         error = vmbus_chan_recv(chan, data, &dlen, &xactid);
  186         KASSERT(error != ENOBUFS, ("icbuf is not large enough"));
  187         if (error)
  188                 return;
  189 
  190         if (dlen < sizeof(*hdr)) {
  191                 device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
  192                 return;
  193         }
  194         hdr = data;
  195 
  196         /*
  197          * Update request, which will be echoed back as response.
  198          */
  199         switch (hdr->ic_type) {
  200         case VMBUS_ICMSG_TYPE_NEGOTIATE:
  201                 error = vmbus_ic_negomsg(sc, data, &dlen,
  202                     VMBUS_TIMESYNC_FWVER, VMBUS_TIMESYNC_MSGVER);
  203                 if (error)
  204                         return;
  205                 if (VMBUS_TIMESYNC_DORTT(sc))
  206                         device_printf(sc->ic_dev, "RTT\n");
  207                 break;
  208 
  209         case VMBUS_ICMSG_TYPE_TIMESYNC:
  210                 if (VMBUS_TIMESYNC_MSGVER4(sc)) {
  211                         const struct vmbus_icmsg_timesync4 *msg4;
  212 
  213                         if (dlen < sizeof(*msg4)) {
  214                                 device_printf(sc->ic_dev, "invalid timesync4 "
  215                                     "len %d\n", dlen);
  216                                 return;
  217                         }
  218                         msg4 = data;
  219                         vmbus_timesync(sc, msg4->ic_hvtime, msg4->ic_sent_tc,
  220                             msg4->ic_tsflags);
  221                 } else {
  222                         const struct vmbus_icmsg_timesync *msg;
  223 
  224                         if (dlen < sizeof(*msg)) {
  225                                 device_printf(sc->ic_dev, "invalid timesync "
  226                                     "len %d\n", dlen);
  227                                 return;
  228                         }
  229                         msg = data;
  230                         vmbus_timesync(sc, msg->ic_hvtime, 0, msg->ic_tsflags);
  231                 }
  232                 break;
  233 
  234         default:
  235                 device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type);
  236                 break;
  237         }
  238 
  239         /*
  240          * Send response by echoing the request back.
  241          */
  242         vmbus_ic_sendresp(sc, chan, data, dlen, xactid);
  243 }
  244 
  245 static int
  246 vmbus_timesync_probe(device_t dev)
  247 {
  248 
  249         return (vmbus_ic_probe(dev, vmbus_timesync_descs));
  250 }
  251 
  252 static int
  253 vmbus_timesync_attach(device_t dev)
  254 {
  255 
  256         return (vmbus_ic_attach(dev, vmbus_timesync_cb));
  257 }

Cache object: b12f82fd00899874206c692b49584949


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