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/efidev/efirtc.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) 2017 Andrew Turner
    3  * All rights reserved.
    4  *
    5  * This software was developed by SRI International and the University of
    6  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
    7  * ("CTSRD"), as part of the DARPA CRASH research programme.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/clock.h>
   38 #include <sys/efi.h>
   39 #include <sys/kernel.h>
   40 #include <sys/module.h>
   41 
   42 #include "clock_if.h"
   43 
   44 static bool efirtc_zeroes_subseconds;
   45 static struct timespec efirtc_resadj;
   46 
   47 static const u_int us_per_s  = 1000000;
   48 static const u_int ns_per_s  = 1000000000;
   49 static const u_int ns_per_us = 1000;
   50 
   51 static void
   52 efirtc_identify(driver_t *driver, device_t parent)
   53 {
   54 
   55         /* Don't add the driver unless we have working runtime services. */
   56         if (efi_rt_ok() != 0)
   57                 return;
   58         if (device_find_child(parent, "efirtc", -1) != NULL)
   59                 return;
   60         if (BUS_ADD_CHILD(parent, 0, "efirtc", -1) == NULL)
   61                 device_printf(parent, "add child failed\n");
   62 }
   63 
   64 static int
   65 efirtc_probe(device_t dev)
   66 {
   67         struct efi_tm tm;
   68         int error;
   69 
   70         /*
   71          * Check whether we can read the time.  This will stop us from attaching
   72          * when there is EFI Runtime support but the gettime function is
   73          * unimplemented, e.g. on some builds of U-Boot.
   74          */
   75         if ((error = efi_get_time(&tm)) != 0) {
   76                 if (bootverbose)
   77                         device_printf(dev, "cannot read EFI realtime clock, "
   78                             "error %d\n", error);
   79                 return (error);
   80         }
   81         device_set_desc(dev, "EFI Realtime Clock");
   82         return (BUS_PROBE_DEFAULT);
   83 }
   84 
   85 static int
   86 efirtc_attach(device_t dev)
   87 {
   88         struct efi_tmcap tmcap;
   89         long res;
   90         int error;
   91 
   92         bzero(&tmcap, sizeof(tmcap));
   93         if ((error = efi_get_time_capabilities(&tmcap)) != 0) {
   94                 device_printf(dev, "cannot get EFI time capabilities");
   95                 return (error);
   96         }
   97 
   98         /* Translate resolution in Hz to tick length in usec. */
   99         if (tmcap.tc_res == 0)
  100                 res = us_per_s; /* 0 is insane, assume 1 Hz. */
  101         else if (tmcap.tc_res > us_per_s)
  102                 res = 1; /* 1us is the best we can represent */
  103         else
  104                 res = us_per_s / tmcap.tc_res;
  105 
  106         /* Clock rounding adjustment is 1/2 of resolution, in nsec. */
  107         efirtc_resadj.tv_nsec = (res * ns_per_us) / 2;
  108 
  109         /* Does the clock zero the subseconds when time is set? */
  110         efirtc_zeroes_subseconds = tmcap.tc_stz;
  111 
  112         /*
  113          * Register.  If the clock zeroes out the subseconds when it's set,
  114          * schedule the SetTime calls to happen just before top-of-second.
  115          */
  116         clock_register_flags(dev, res, CLOCKF_SETTIME_NO_ADJ);
  117         if (efirtc_zeroes_subseconds)
  118                 clock_schedule(dev, ns_per_s - ns_per_us);
  119 
  120         return (0);
  121 }
  122 
  123 static int
  124 efirtc_detach(device_t dev)
  125 {
  126 
  127         clock_unregister(dev);
  128         return (0);
  129 }
  130 
  131 static int
  132 efirtc_gettime(device_t dev, struct timespec *ts)
  133 {
  134         struct clocktime ct;
  135         struct efi_tm tm;
  136         int error;
  137 
  138         error = efi_get_time(&tm);
  139         if (error != 0)
  140                 return (error);
  141 
  142         ct.sec = tm.tm_sec;
  143         ct.min = tm.tm_min;
  144         ct.hour = tm.tm_hour;
  145         ct.day = tm.tm_mday;
  146         ct.mon = tm.tm_mon;
  147         ct.year = tm.tm_year;
  148         ct.nsec = tm.tm_nsec;
  149 
  150         clock_dbgprint_ct(dev, CLOCK_DBG_READ, &ct);
  151         return (clock_ct_to_ts(&ct, ts));
  152 }
  153 
  154 static int
  155 efirtc_settime(device_t dev, struct timespec *ts)
  156 {
  157         struct clocktime ct;
  158         struct efi_tm tm;
  159 
  160         /*
  161          * We request a timespec with no resolution-adjustment so that we can
  162          * apply it ourselves based on whether or not the clock zeroes the
  163          * sub-second part of the time when setting the time.
  164          */
  165         ts->tv_sec -= utc_offset();
  166         if (!efirtc_zeroes_subseconds)
  167                 timespecadd(ts, &efirtc_resadj, ts);
  168         
  169         clock_ts_to_ct(ts, &ct);
  170         clock_dbgprint_ct(dev, CLOCK_DBG_WRITE, &ct);
  171 
  172         bzero(&tm, sizeof(tm));
  173         tm.tm_sec = ct.sec;
  174         tm.tm_min = ct.min;
  175         tm.tm_hour = ct.hour;
  176         tm.tm_mday = ct.day;
  177         tm.tm_mon = ct.mon;
  178         tm.tm_year = ct.year;
  179         tm.tm_nsec = ct.nsec;
  180 
  181         return (efi_set_time(&tm));
  182 }
  183 
  184 static device_method_t efirtc_methods[] = {
  185         /* Device interface */
  186         DEVMETHOD(device_identify,      efirtc_identify),
  187         DEVMETHOD(device_probe,         efirtc_probe),
  188         DEVMETHOD(device_attach,        efirtc_attach),
  189         DEVMETHOD(device_detach,        efirtc_detach),
  190 
  191         /* Clock interface */
  192         DEVMETHOD(clock_gettime,        efirtc_gettime),
  193         DEVMETHOD(clock_settime,        efirtc_settime),
  194 
  195         DEVMETHOD_END
  196 };
  197 
  198 static driver_t efirtc_driver = {
  199         "efirtc",
  200         efirtc_methods,
  201         0
  202 };
  203 
  204 DRIVER_MODULE(efirtc, nexus, efirtc_driver, 0, 0);
  205 MODULE_VERSION(efirtc, 1);
  206 MODULE_DEPEND(efirtc, efirt, 1, 1, 1);

Cache object: 21228ea15fd0738a797230b5a0225fd5


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