Index: head/sys/arm/arm/mpcore_timer.c =================================================================== --- head/sys/arm/arm/mpcore_timer.c (revision 321685) +++ head/sys/arm/arm/mpcore_timer.c (revision 321686) @@ -1,560 +1,560 @@ /*- * Copyright (c) 2011 The FreeBSD Foundation * All rights reserved. * * Developed by Ben Gray * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /** * The ARM Cortex-A9 core can support a global timer plus a private and * watchdog timer per core. This driver reserves memory and interrupt * resources for accessing both timer register sets, these resources are * stored globally and used to setup the timecount and eventtimer. * * The timecount timer uses the global 64-bit counter, whereas the * per-CPU eventtimer uses the private 32-bit counters. * * * REF: ARM Cortex-A9 MPCore, Technical Reference Manual (rev. r2p2) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For arm_set_delay */ #include #include #include #include #include /* Private (per-CPU) timer register map */ #define PRV_TIMER_LOAD 0x0000 #define PRV_TIMER_COUNT 0x0004 #define PRV_TIMER_CTRL 0x0008 #define PRV_TIMER_INTR 0x000C #define PRV_TIMER_CTR_PRESCALER_SHIFT 8 #define PRV_TIMER_CTRL_IRQ_ENABLE (1UL << 2) #define PRV_TIMER_CTRL_AUTO_RELOAD (1UL << 1) #define PRV_TIMER_CTRL_TIMER_ENABLE (1UL << 0) #define PRV_TIMER_INTR_EVENT (1UL << 0) /* Global timer register map */ #define GBL_TIMER_COUNT_LOW 0x0000 #define GBL_TIMER_COUNT_HIGH 0x0004 #define GBL_TIMER_CTRL 0x0008 #define GBL_TIMER_INTR 0x000C #define GBL_TIMER_CTR_PRESCALER_SHIFT 8 #define GBL_TIMER_CTRL_AUTO_INC (1UL << 3) #define GBL_TIMER_CTRL_IRQ_ENABLE (1UL << 2) #define GBL_TIMER_CTRL_COMP_ENABLE (1UL << 1) #define GBL_TIMER_CTRL_TIMER_ENABLE (1UL << 0) #define GBL_TIMER_INTR_EVENT (1UL << 0) struct arm_tmr_softc { device_t dev; int irqrid; int memrid; struct resource * gbl_mem; struct resource * prv_mem; struct resource * prv_irq; uint64_t clkfreq; struct eventtimer et; }; static struct eventtimer *arm_tmr_et; static struct timecounter *arm_tmr_tc; static uint64_t arm_tmr_freq; static boolean_t arm_tmr_freq_varies; #define tmr_prv_read_4(sc, reg) bus_read_4((sc)->prv_mem, reg) #define tmr_prv_write_4(sc, reg, val) bus_write_4((sc)->prv_mem, reg, val) #define tmr_gbl_read_4(sc, reg) bus_read_4((sc)->gbl_mem, reg) #define tmr_gbl_write_4(sc, reg, val) bus_write_4((sc)->gbl_mem, reg, val) static void arm_tmr_delay(int, void *); static timecounter_get_t arm_tmr_get_timecount; static struct timecounter arm_tmr_timecount = { .tc_name = "MPCore", .tc_get_timecount = arm_tmr_get_timecount, .tc_poll_pps = NULL, .tc_counter_mask = ~0u, .tc_frequency = 0, .tc_quality = 800, }; #define TMR_GBL 0x01 #define TMR_PRV 0x02 #define TMR_BOTH (TMR_GBL | TMR_PRV) #define TMR_NONE 0 static struct ofw_compat_data compat_data[] = { {"arm,mpcore-timers", TMR_BOTH}, /* Non-standard, FreeBSD. */ {"arm,cortex-a9-global-timer", TMR_GBL}, {"arm,cortex-a5-global-timer", TMR_GBL}, {"arm,cortex-a9-twd-timer", TMR_PRV}, {"arm,cortex-a5-twd-timer", TMR_PRV}, {"arm,arm11mp-twd-timer", TMR_PRV}, {NULL, TMR_NONE} }; /** * arm_tmr_get_timecount - reads the timecount (global) timer * @tc: pointer to arm_tmr_timecount struct * * We only read the lower 32-bits, the timecount stuff only uses 32-bits * so (for now?) ignore the upper 32-bits. * * RETURNS * The lower 32-bits of the counter. */ static unsigned arm_tmr_get_timecount(struct timecounter *tc) { struct arm_tmr_softc *sc; sc = tc->tc_priv; return (tmr_gbl_read_4(sc, GBL_TIMER_COUNT_LOW)); } /** * arm_tmr_start - starts the eventtimer (private) timer * @et: pointer to eventtimer struct * @first: the number of seconds and fractional sections to trigger in * @period: the period (in seconds and fractional sections) to set * * If the eventtimer is required to be in oneshot mode, period will be * NULL and first will point to the time to trigger. If in periodic mode * period will contain the time period and first may optionally contain * the time for the first period. * * RETURNS * Always returns 0 */ static int arm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct arm_tmr_softc *sc; uint32_t load, count; uint32_t ctrl; sc = et->et_priv; tmr_prv_write_4(sc, PRV_TIMER_CTRL, 0); tmr_prv_write_4(sc, PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT); ctrl = PRV_TIMER_CTRL_IRQ_ENABLE | PRV_TIMER_CTRL_TIMER_ENABLE; if (period != 0) { load = ((uint32_t)et->et_frequency * period) >> 32; ctrl |= PRV_TIMER_CTRL_AUTO_RELOAD; } else load = 0; if (first != 0) count = (uint32_t)((et->et_frequency * first) >> 32); else count = load; tmr_prv_write_4(sc, PRV_TIMER_LOAD, load); tmr_prv_write_4(sc, PRV_TIMER_COUNT, count); tmr_prv_write_4(sc, PRV_TIMER_CTRL, ctrl); return (0); } /** * arm_tmr_stop - stops the eventtimer (private) timer * @et: pointer to eventtimer struct * * Simply stops the private timer by clearing all bits in the ctrl register. * * RETURNS * Always returns 0 */ static int arm_tmr_stop(struct eventtimer *et) { struct arm_tmr_softc *sc; sc = et->et_priv; tmr_prv_write_4(sc, PRV_TIMER_CTRL, 0); tmr_prv_write_4(sc, PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT); return (0); } /** * arm_tmr_intr - ISR for the eventtimer (private) timer * @arg: pointer to arm_tmr_softc struct * * Clears the event register and then calls the eventtimer callback. * * RETURNS * Always returns FILTER_HANDLED */ static int arm_tmr_intr(void *arg) { struct arm_tmr_softc *sc; sc = arg; tmr_prv_write_4(sc, PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT); if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); return (FILTER_HANDLED); } /** * arm_tmr_probe - timer probe routine * @dev: new device * * The probe function returns success when probed with the fdt compatible * string set to "arm,mpcore-timers". * * RETURNS * BUS_PROBE_DEFAULT if the fdt device is compatible, otherwise ENXIO. */ static int arm_tmr_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == TMR_NONE) return (ENXIO); device_set_desc(dev, "ARM MPCore Timers"); return (BUS_PROBE_DEFAULT); } static int attach_tc(struct arm_tmr_softc *sc) { int rid; if (arm_tmr_tc != NULL) return (EBUSY); rid = sc->memrid; sc->gbl_mem = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->gbl_mem == NULL) { device_printf(sc->dev, "could not allocate gbl mem resources\n"); return (ENXIO); } tmr_gbl_write_4(sc, GBL_TIMER_CTRL, 0x00000000); arm_tmr_timecount.tc_frequency = sc->clkfreq; arm_tmr_timecount.tc_priv = sc; tc_init(&arm_tmr_timecount); arm_tmr_tc = &arm_tmr_timecount; tmr_gbl_write_4(sc, GBL_TIMER_CTRL, GBL_TIMER_CTRL_TIMER_ENABLE); return (0); } static int attach_et(struct arm_tmr_softc *sc) { void *ihl; int irid, mrid; if (arm_tmr_et != NULL) return (EBUSY); mrid = sc->memrid; sc->prv_mem = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &mrid, RF_ACTIVE); if (sc->prv_mem == NULL) { device_printf(sc->dev, "could not allocate prv mem resources\n"); return (ENXIO); } tmr_prv_write_4(sc, PRV_TIMER_CTRL, 0x00000000); irid = sc->irqrid; sc->prv_irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irid, RF_ACTIVE); if (sc->prv_irq == NULL) { bus_release_resource(sc->dev, SYS_RES_MEMORY, mrid, sc->prv_mem); device_printf(sc->dev, "could not allocate prv irq resources\n"); return (ENXIO); } if (bus_setup_intr(sc->dev, sc->prv_irq, INTR_TYPE_CLK, arm_tmr_intr, NULL, sc, &ihl) != 0) { bus_release_resource(sc->dev, SYS_RES_MEMORY, mrid, sc->prv_mem); bus_release_resource(sc->dev, SYS_RES_IRQ, irid, sc->prv_irq); device_printf(sc->dev, "unable to setup the et irq handler.\n"); return (ENXIO); } /* * Setup and register the eventtimer. Most event timers set their min * and max period values to some value calculated from the clock * frequency. We might not know yet what our runtime clock frequency * will be, so we just use some safe values. A max of 2 seconds ensures * that even if our base clock frequency is 2GHz (meaning a 4GHz CPU), * we won't overflow our 32-bit timer count register. A min of 20 * nanoseconds is pretty much completely arbitrary. */ sc->et.et_name = "MPCore"; sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; sc->et.et_quality = 1000; sc->et.et_frequency = sc->clkfreq; - sc->et.et_min_period = 20 * SBT_1NS; + sc->et.et_min_period = nstosbt(20); sc->et.et_max_period = 2 * SBT_1S; sc->et.et_start = arm_tmr_start; sc->et.et_stop = arm_tmr_stop; sc->et.et_priv = sc; et_register(&sc->et); arm_tmr_et = &sc->et; return (0); } /** * arm_tmr_attach - attaches the timer to the simplebus * @dev: new device * * Reserves memory and interrupt resources, stores the softc structure * globally and registers both the timecount and eventtimer objects. * * RETURNS * Zero on success or ENXIO if an error occuried. */ static int arm_tmr_attach(device_t dev) { struct arm_tmr_softc *sc; phandle_t node; pcell_t clock; int et_err, tc_err, tmrtype; sc = device_get_softc(dev); sc->dev = dev; if (arm_tmr_freq_varies) { sc->clkfreq = arm_tmr_freq; } else { if (arm_tmr_freq != 0) { sc->clkfreq = arm_tmr_freq; } else { /* Get the base clock frequency */ node = ofw_bus_get_node(dev); if ((OF_getencprop(node, "clock-frequency", &clock, sizeof(clock))) <= 0) { device_printf(dev, "missing clock-frequency " "attribute in FDT\n"); return (ENXIO); } sc->clkfreq = clock; } } tmrtype = ofw_bus_search_compatible(dev, compat_data)->ocd_data; tc_err = ENXIO; et_err = ENXIO; /* * If we're handling the global timer and it is fixed-frequency, set it * up to use as a timecounter. If it's variable frequency it won't work * as a timecounter. We also can't use it for DELAY(), so hopefully the * platform provides its own implementation. If it doesn't, ours will * get used, but since the frequency isn't set, it will only use the * bogus loop counter. */ if (tmrtype & TMR_GBL) { if (!arm_tmr_freq_varies) tc_err = attach_tc(sc); else if (bootverbose) device_printf(sc->dev, "not using variable-frequency device as timecounter"); sc->memrid++; sc->irqrid++; } /* If we are handling the private timer, set it up as an eventtimer. */ if (tmrtype & TMR_PRV) { et_err = attach_et(sc); } /* * If we didn't successfully set up a timecounter or eventtimer then we * didn't actually attach at all, return error. */ if (tc_err != 0 && et_err != 0) { return (ENXIO); } #ifdef PLATFORM /* * We can register as the DELAY() implementation only if we successfully * set up the global timer. */ if (tc_err == 0) arm_set_delay(arm_tmr_delay, sc); #endif return (0); } static device_method_t arm_tmr_methods[] = { DEVMETHOD(device_probe, arm_tmr_probe), DEVMETHOD(device_attach, arm_tmr_attach), { 0, 0 } }; static driver_t arm_tmr_driver = { "mp_tmr", arm_tmr_methods, sizeof(struct arm_tmr_softc), }; static devclass_t arm_tmr_devclass; EARLY_DRIVER_MODULE(mp_tmr, simplebus, arm_tmr_driver, arm_tmr_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); EARLY_DRIVER_MODULE(mp_tmr, ofwbus, arm_tmr_driver, arm_tmr_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); /* * Handle a change in clock frequency. The mpcore timer runs at half the CPU * frequency. When the CPU frequency changes due to power-saving or thermal * management, the platform-specific code that causes the frequency change calls * this routine to inform the clock driver, and we in turn inform the event * timer system, which actually updates the value in et->frequency for us and * reschedules the current event(s) in a way that's atomic with respect to * start/stop/intr code that may be running on various CPUs at the time of the * call. * * This routine can also be called by a platform's early init code. If the * value passed is ARM_TMR_FREQUENCY_VARIES, that will cause the attach() code * to register as an eventtimer, but not a timecounter. If the value passed in * is any other non-zero value it is used as the fixed frequency for the timer. */ void arm_tmr_change_frequency(uint64_t newfreq) { if (newfreq == ARM_TMR_FREQUENCY_VARIES) { arm_tmr_freq_varies = true; return; } arm_tmr_freq = newfreq; if (arm_tmr_et != NULL) et_change_frequency(arm_tmr_et, newfreq); } static void arm_tmr_delay(int usec, void *arg) { struct arm_tmr_softc *sc = arg; int32_t counts_per_usec; int32_t counts; uint32_t first, last; /* Get the number of times to count */ counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1); /* * Clamp the timeout at a maximum value (about 32 seconds with * a 66MHz clock). *Nobody* should be delay()ing for anywhere * near that length of time and if they are, they should be hung * out to dry. */ if (usec >= (0x80000000U / counts_per_usec)) counts = (0x80000000U / counts_per_usec) - 1; else counts = usec * counts_per_usec; first = tmr_gbl_read_4(sc, GBL_TIMER_COUNT_LOW); while (counts > 0) { last = tmr_gbl_read_4(sc, GBL_TIMER_COUNT_LOW); counts -= (int32_t)(last - first); first = last; } } #ifndef PLATFORM /** * DELAY - Delay for at least usec microseconds. * @usec: number of microseconds to delay by * * This function is called all over the kernel and is suppose to provide a * consistent delay. This function may also be called before the console * is setup so no printf's can be called here. * * RETURNS: * nothing */ void DELAY(int usec) { struct arm_tmr_softc *sc; int32_t counts; /* Check the timers are setup, if not just use a for loop for the meantime */ if (arm_tmr_tc == NULL || arm_tmr_timecount.tc_frequency == 0) { for (; usec > 0; usec--) for (counts = 200; counts > 0; counts--) cpufunc_nullop(); /* Prevent gcc from optimizing * out the loop */ } else { sc = arm_tmr_tc->tc_priv; arm_tmr_delay(usec, sc); } } #endif Index: head/sys/compat/linuxkpi/common/src/linux_hrtimer.c =================================================================== --- head/sys/compat/linuxkpi/common/src/linux_hrtimer.c (revision 321685) +++ head/sys/compat/linuxkpi/common/src/linux_hrtimer.c (revision 321686) @@ -1,108 +1,108 @@ /*- * Copyright (c) 2017 Mark Johnston * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include /* hrtimer flags */ #define HRTIMER_ACTIVE 0x01 static void hrtimer_call_handler(void *arg) { struct hrtimer *hrtimer; enum hrtimer_restart ret; hrtimer = arg; ret = hrtimer->function(hrtimer); MPASS(ret == HRTIMER_NORESTART); hrtimer->flags &= ~HRTIMER_ACTIVE; } bool linux_hrtimer_active(struct hrtimer *hrtimer) { bool ret; mtx_lock(&hrtimer->mtx); ret = (hrtimer->flags & HRTIMER_ACTIVE) != 0; mtx_unlock(&hrtimer->mtx); return (ret); } int linux_hrtimer_cancel(struct hrtimer *hrtimer) { if (!hrtimer_active(hrtimer)) return (0); (void)callout_drain(&hrtimer->callout); return (1); } void linux_hrtimer_init(struct hrtimer *hrtimer) { hrtimer->function = NULL; hrtimer->flags = 0; mtx_init(&hrtimer->mtx, "hrtimer", NULL, MTX_DEF | MTX_RECURSE); callout_init_mtx(&hrtimer->callout, &hrtimer->mtx, 0); } void linux_hrtimer_set_expires(struct hrtimer *hrtimer __unused, ktime_t time __unused) { } void linux_hrtimer_start(struct hrtimer *hrtimer, ktime_t time) { linux_hrtimer_start_range_ns(hrtimer, time, 0); } void linux_hrtimer_start_range_ns(struct hrtimer *hrtimer, ktime_t time, int64_t nsec) { mtx_lock(&hrtimer->mtx); - callout_reset_sbt(&hrtimer->callout, time.tv64 * SBT_1NS, - nsec * SBT_1NS, hrtimer_call_handler, hrtimer, 0); + callout_reset_sbt(&hrtimer->callout, nstosbt(time.tv64), nstosbt(nsec), + hrtimer_call_handler, hrtimer, 0); hrtimer->flags |= HRTIMER_ACTIVE; mtx_unlock(&hrtimer->mtx); } Index: head/sys/dev/ow/owc_gpiobus.c =================================================================== --- head/sys/dev/ow/owc_gpiobus.c (revision 321685) +++ head/sys/dev/ow/owc_gpiobus.c (revision 321686) @@ -1,420 +1,420 @@ /*- * Copyright (c) 2015 M. Warner Losh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #include #endif #include #include "gpiobus_if.h" #include #define OW_PIN 0 #define OWC_GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define OWC_GPIOBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define OWC_GPIOBUS_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ "owc_gpiobus", MTX_DEF) #define OWC_GPIOBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); struct owc_gpiobus_softc { device_t sc_dev; device_t sc_busdev; struct mtx sc_mtx; }; static int owc_gpiobus_probe(device_t); static int owc_gpiobus_attach(device_t); static int owc_gpiobus_detach(device_t); #ifdef FDT static void owc_gpiobus_identify(driver_t *driver, device_t bus) { phandle_t w1, root; /* * Find all the 1-wire bus pseudo-nodes that are * at the top level of the FDT. Would be nice to * somehow preserve the node name of these busses, * but there's no good place to put it. The driver's * name is used for the device name, and the 1-wire * bus overwrites the description. */ root = OF_finddevice("/"); if (root == 0) return; for (w1 = OF_child(root); w1 != 0; w1 = OF_peer(w1)) { if (!fdt_is_compatible_strict(w1, "w1-gpio")) continue; if (!OF_hasprop(w1, "gpios")) continue; ofw_gpiobus_add_fdt_child(bus, driver->name, w1); } } #endif static int owc_gpiobus_probe(device_t dev) { #ifdef FDT if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "w1-gpio")) { device_set_desc(dev, "FDT GPIO attached one-wire bus"); return (BUS_PROBE_DEFAULT); } return (ENXIO); #else device_set_desc(dev, "GPIO attached one-wire bus"); return 0; #endif } static int owc_gpiobus_attach(device_t dev) { struct owc_gpiobus_softc *sc; device_t *kids; int nkid; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_busdev = device_get_parent(dev); OWC_GPIOBUS_LOCK_INIT(sc); nkid = 0; if (device_get_children(dev, &kids, &nkid) == 0) free(kids, M_TEMP); if (nkid == 0) device_add_child(dev, "ow", -1); bus_generic_attach(dev); return (0); } static int owc_gpiobus_detach(device_t dev) { struct owc_gpiobus_softc *sc; sc = device_get_softc(dev); OWC_GPIOBUS_LOCK_DESTROY(sc); bus_generic_detach(dev); return (0); } /* * In the diagrams below, R is driven by the resistor pullup, M is driven by the * master, and S is driven by the slave / target. */ /* * These macros let what why we're doing stuff shine in the code * below, and let the how be confined to here. */ #define GETBUS(sc) GPIOBUS_ACQUIRE_BUS((sc)->sc_busdev, \ (sc)->sc_dev, GPIOBUS_WAIT) #define RELBUS(sc) GPIOBUS_RELEASE_BUS((sc)->sc_busdev, \ (sc)->sc_dev) #define OUTPIN(sc) GPIOBUS_PIN_SETFLAGS((sc)->sc_busdev, \ (sc)->sc_dev, OW_PIN, GPIO_PIN_OUTPUT) #define INPIN(sc) GPIOBUS_PIN_SETFLAGS((sc)->sc_busdev, \ (sc)->sc_dev, OW_PIN, GPIO_PIN_INPUT) #define GETPIN(sc, bit) GPIOBUS_PIN_GET((sc)->sc_busdev, \ (sc)->sc_dev, OW_PIN, bit) #define LOW(sc) GPIOBUS_PIN_SET((sc)->sc_busdev, \ (sc)->sc_dev, OW_PIN, GPIO_PIN_LOW) /* * WRITE-ONE (see owll_if.m for timings) From Figure 4-1 AN-937 * * |<---------tSLOT---->|<-tREC->| * High RRRRM | RRRRRRRRRRRR|RRRRRRRRM * M | R | | | M * M| R | | | M * Low MMMMMMM | | | MMMMMM... * |<-tLOW1->| | | * |<------15us--->| | * |<--------60us---->| */ static int owc_gpiobus_write_one(device_t dev, struct ow_timing *t) { struct owc_gpiobus_softc *sc; int error; sc = device_get_softc(dev); error = GETBUS(sc); if (error != 0) return error; critical_enter(); /* Force low */ OUTPIN(sc); LOW(sc); DELAY(t->t_low1); /* Allow resistor to float line high */ INPIN(sc); DELAY(t->t_slot - t->t_low1 + t->t_rec); critical_exit(); RELBUS(sc); return 0; } /* * WRITE-ZERO (see owll_if.m for timings) From Figure 4-2 AN-937 * * |<---------tSLOT------>|<-tREC->| * High RRRRM | | |RRRRRRRM * M | | R M * M| | | |R M * Low MMMMMMMMMMMMMMMMMMMMMR MMMMMM... * |<--15us->| | | * |<------60us--->| | * |<-------tLOW0------>| */ static int owc_gpiobus_write_zero(device_t dev, struct ow_timing *t) { struct owc_gpiobus_softc *sc; int error; sc = device_get_softc(dev); error = GETBUS(sc); if (error != 0) return error; critical_enter(); /* Force low */ OUTPIN(sc); LOW(sc); DELAY(t->t_low0); /* Allow resistor to float line high */ INPIN(sc); DELAY(t->t_slot - t->t_low0 + t->t_rec); critical_exit(); RELBUS(sc); return 0; } /* * READ-DATA (see owll_if.m for timings) From Figure 4-3 AN-937 * * |<---------tSLOT------>|<-tREC->| * High RRRRM | rrrrrrrrrrrrrrrRRRRRRRM * M | r | R M * M| r | |R M * Low MMMMMMMSSSSSSSSSSSSSSR MMMMMM... * |< sample > | * |<------tRDV---->| | * ->| |<-tRELEASE * * r -- allowed to pull high via the resitor when slave writes a 1-bit * */ static int owc_gpiobus_read_data(device_t dev, struct ow_timing *t, int *bit) { struct owc_gpiobus_softc *sc; int error, sample; sbintime_t then, now; sc = device_get_softc(dev); error = GETBUS(sc); if (error != 0) return error; /* Force low for t_lowr microseconds */ then = sbinuptime(); OUTPIN(sc); LOW(sc); DELAY(t->t_lowr); /* * Slave is supposed to hold the line low for t_rdv microseconds for 0 * and immediately float it high for a 1. This is measured from the * master's pushing the line low. */ INPIN(sc); critical_enter(); do { now = sbinuptime(); GETPIN(sc, &sample); - } while ((now - then) / SBT_1US < t->t_rdv + 2 && sample == 0); + } while (sbttous(now - then) < t->t_rdv + 2 && sample == 0); critical_exit(); - if ((now - then) / SBT_1NS < t->t_rdv * 1000) + if (sbttons(now - then) < t->t_rdv * 1000) *bit = 1; else *bit = 0; /* Wait out the rest of t_slot */ do { now = sbinuptime(); } while ((now - then) / SBT_1US < t->t_slot); RELBUS(sc); return 0; } /* * RESET AND PRESENCE PULSE (see owll_if.m for timings) From Figure 4-4 AN-937 * * |<---------tRSTH------------>| * High RRRM | | RRRRRRRS | RRRR RRM * M | |R| |S | R M * M| R | | S |R M * Low MMMMMMMM MMMMMM| | | SSSSSSSSSS MMMMMM * |<----tRSTL--->| | |<-tPDL---->| * | ->| |<-tR | | * || * * Note: for Regular Speed operations, tRSTL + tR should be less than 960us to * avoid interferring with other devices on the bus */ static int owc_gpiobus_reset_and_presence(device_t dev, struct ow_timing *t, int *bit) { struct owc_gpiobus_softc *sc; int error; int buf = -1; sc = device_get_softc(dev); error = GETBUS(sc); if (error != 0) return error; /* * Read the current state of the bus. The steady state of an idle bus is * high. Badly wired buses that are missing the required pull up, or * that have a short circuit to ground cause all kinds of mischief when * we try to read them later. Return EIO and release the bus if the bus * is currently low. */ INPIN(sc); GETPIN(sc, &buf); if (buf == 0) { *bit = -1; RELBUS(sc); return EIO; } critical_enter(); /* Force low */ OUTPIN(sc); LOW(sc); DELAY(t->t_rstl); /* Allow resistor to float line high and then wait for reset pulse */ INPIN(sc); DELAY(t->t_pdh + t->t_pdl / 2); /* Read presence pulse */ GETPIN(sc, &buf); *bit = !!buf; critical_exit(); DELAY(t->t_rsth - (t->t_pdh + t->t_pdl / 2)); /* Timing not critical for this one */ /* * Read the state of the bus after we've waited past the end of the rest * window. It should return to high. If it is low, then we have some * problem and should abort the reset. */ GETPIN(sc, &buf); if (buf == 0) { *bit = -1; RELBUS(sc); return EIO; } RELBUS(sc); return 0; } static devclass_t owc_gpiobus_devclass; static device_method_t owc_gpiobus_methods[] = { /* Device interface */ #ifdef FDT DEVMETHOD(device_identify, owc_gpiobus_identify), #endif DEVMETHOD(device_probe, owc_gpiobus_probe), DEVMETHOD(device_attach, owc_gpiobus_attach), DEVMETHOD(device_detach, owc_gpiobus_detach), DEVMETHOD(owll_write_one, owc_gpiobus_write_one), DEVMETHOD(owll_write_zero, owc_gpiobus_write_zero), DEVMETHOD(owll_read_data, owc_gpiobus_read_data), DEVMETHOD(owll_reset_and_presence, owc_gpiobus_reset_and_presence), { 0, 0 } }; static driver_t owc_gpiobus_driver = { "owc", owc_gpiobus_methods, sizeof(struct owc_gpiobus_softc), }; DRIVER_MODULE(owc_gpiobus_fdt, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); MODULE_DEPEND(owc_gpiobus_fdt, ow, 1, 1, 1); Index: head/sys/sys/time.h =================================================================== --- head/sys/sys/time.h (revision 321685) +++ head/sys/sys/time.h (revision 321686) @@ -1,501 +1,546 @@ /*- * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)time.h 8.5 (Berkeley) 5/4/95 * $FreeBSD$ */ #ifndef _SYS_TIME_H_ #define _SYS_TIME_H_ #include #include #include struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of dst correction */ }; #define DST_NONE 0 /* not on dst */ #define DST_USA 1 /* USA style dst */ #define DST_AUST 2 /* Australian style dst */ #define DST_WET 3 /* Western European dst */ #define DST_MET 4 /* Middle European dst */ #define DST_EET 5 /* Eastern European dst */ #define DST_CAN 6 /* Canada */ #if __BSD_VISIBLE struct bintime { time_t sec; uint64_t frac; }; static __inline void bintime_addx(struct bintime *_bt, uint64_t _x) { uint64_t _u; _u = _bt->frac; _bt->frac += _x; if (_u > _bt->frac) _bt->sec++; } static __inline void bintime_add(struct bintime *_bt, const struct bintime *_bt2) { uint64_t _u; _u = _bt->frac; _bt->frac += _bt2->frac; if (_u > _bt->frac) _bt->sec++; _bt->sec += _bt2->sec; } static __inline void bintime_sub(struct bintime *_bt, const struct bintime *_bt2) { uint64_t _u; _u = _bt->frac; _bt->frac -= _bt2->frac; if (_u < _bt->frac) _bt->sec--; _bt->sec -= _bt2->sec; } static __inline void bintime_mul(struct bintime *_bt, u_int _x) { uint64_t _p1, _p2; _p1 = (_bt->frac & 0xffffffffull) * _x; _p2 = (_bt->frac >> 32) * _x + (_p1 >> 32); _bt->sec *= _x; _bt->sec += (_p2 >> 32); _bt->frac = (_p2 << 32) | (_p1 & 0xffffffffull); } static __inline void bintime_shift(struct bintime *_bt, int _exp) { if (_exp > 0) { _bt->sec <<= _exp; _bt->sec |= _bt->frac >> (64 - _exp); _bt->frac <<= _exp; } else if (_exp < 0) { _bt->frac >>= -_exp; _bt->frac |= (uint64_t)_bt->sec << (64 + _exp); _bt->sec >>= -_exp; } } #define bintime_clear(a) ((a)->sec = (a)->frac = 0) #define bintime_isset(a) ((a)->sec || (a)->frac) #define bintime_cmp(a, b, cmp) \ (((a)->sec == (b)->sec) ? \ ((a)->frac cmp (b)->frac) : \ ((a)->sec cmp (b)->sec)) #define SBT_1S ((sbintime_t)1 << 32) #define SBT_1M (SBT_1S * 60) #define SBT_1MS (SBT_1S / 1000) #define SBT_1US (SBT_1S / 1000000) -#define SBT_1NS (SBT_1S / 1000000000) +#define SBT_1NS (SBT_1S / 1000000000) /* beware rounding, see nstosbt() */ #define SBT_MAX 0x7fffffffffffffffLL static __inline int sbintime_getsec(sbintime_t _sbt) { return (_sbt >> 32); } static __inline sbintime_t bttosbt(const struct bintime _bt) { return (((sbintime_t)_bt.sec << 32) + (_bt.frac >> 32)); } static __inline struct bintime sbttobt(sbintime_t _sbt) { struct bintime _bt; _bt.sec = _sbt >> 32; _bt.frac = _sbt << 32; return (_bt); } +/* + * Decimal<->sbt conversions. Multiplying or dividing by SBT_1NS results in + * large roundoff errors which sbttons() and nstosbt() avoid. Millisecond and + * microsecond functions are also provided for completeness. + */ +static __inline int64_t +sbttons(sbintime_t _sbt) +{ + + return ((1000000000 * _sbt) >> 32); +} + +static __inline sbintime_t +nstosbt(int64_t _ns) +{ + + return ((_ns * (((uint64_t)1 << 63) / 500000000) >> 32)); +} + +static __inline int64_t +sbttous(sbintime_t _sbt) +{ + + return ((1000000 * _sbt) >> 32); +} + +static __inline sbintime_t +ustosbt(int64_t _us) +{ + + return ((_us * (((uint64_t)1 << 63) / 500000) >> 32)); +} + +static __inline int64_t +sbttoms(sbintime_t _sbt) +{ + + return ((1000 * _sbt) >> 32); +} + +static __inline sbintime_t +mstosbt(int64_t _ms) +{ + + return ((_ms * (((uint64_t)1 << 63) / 500) >> 32)); +} + /*- * Background information: * * When converting between timestamps on parallel timescales of differing * resolutions it is historical and scientific practice to round down rather * than doing 4/5 rounding. * * The date changes at midnight, not at noon. * * Even at 15:59:59.999999999 it's not four'o'clock. * * time_second ticks after N.999999999 not after N.4999999999 */ static __inline void bintime2timespec(const struct bintime *_bt, struct timespec *_ts) { _ts->tv_sec = _bt->sec; _ts->tv_nsec = ((uint64_t)1000000000 * (uint32_t)(_bt->frac >> 32)) >> 32; } static __inline void timespec2bintime(const struct timespec *_ts, struct bintime *_bt) { _bt->sec = _ts->tv_sec; /* 18446744073 = int(2^64 / 1000000000) */ _bt->frac = _ts->tv_nsec * (uint64_t)18446744073LL; } static __inline void bintime2timeval(const struct bintime *_bt, struct timeval *_tv) { _tv->tv_sec = _bt->sec; _tv->tv_usec = ((uint64_t)1000000 * (uint32_t)(_bt->frac >> 32)) >> 32; } static __inline void timeval2bintime(const struct timeval *_tv, struct bintime *_bt) { _bt->sec = _tv->tv_sec; /* 18446744073709 = int(2^64 / 1000000) */ _bt->frac = _tv->tv_usec * (uint64_t)18446744073709LL; } static __inline struct timespec sbttots(sbintime_t _sbt) { struct timespec _ts; _ts.tv_sec = _sbt >> 32; - _ts.tv_nsec = ((uint64_t)1000000000 * (uint32_t)_sbt) >> 32; + _ts.tv_nsec = sbttons((uint32_t)_sbt); return (_ts); } static __inline sbintime_t tstosbt(struct timespec _ts) { - return (((sbintime_t)_ts.tv_sec << 32) + - (_ts.tv_nsec * (((uint64_t)1 << 63) / 500000000) >> 32)); + return (((sbintime_t)_ts.tv_sec << 32) + nstosbt(_ts.tv_nsec)); } static __inline struct timeval sbttotv(sbintime_t _sbt) { struct timeval _tv; _tv.tv_sec = _sbt >> 32; - _tv.tv_usec = ((uint64_t)1000000 * (uint32_t)_sbt) >> 32; + _tv.tv_usec = sbttous((uint32_t)_sbt); return (_tv); } static __inline sbintime_t tvtosbt(struct timeval _tv) { - return (((sbintime_t)_tv.tv_sec << 32) + - (_tv.tv_usec * (((uint64_t)1 << 63) / 500000) >> 32)); + return (((sbintime_t)_tv.tv_sec << 32) + ustosbt(_tv.tv_usec)); } #endif /* __BSD_VISIBLE */ #ifdef _KERNEL /* Operations on timespecs */ #define timespecclear(tvp) ((tvp)->tv_sec = (tvp)->tv_nsec = 0) #define timespecisset(tvp) ((tvp)->tv_sec || (tvp)->tv_nsec) #define timespeccmp(tvp, uvp, cmp) \ (((tvp)->tv_sec == (uvp)->tv_sec) ? \ ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ ((tvp)->tv_sec cmp (uvp)->tv_sec)) #define timespecadd(vvp, uvp) \ do { \ (vvp)->tv_sec += (uvp)->tv_sec; \ (vvp)->tv_nsec += (uvp)->tv_nsec; \ if ((vvp)->tv_nsec >= 1000000000) { \ (vvp)->tv_sec++; \ (vvp)->tv_nsec -= 1000000000; \ } \ } while (0) #define timespecsub(vvp, uvp) \ do { \ (vvp)->tv_sec -= (uvp)->tv_sec; \ (vvp)->tv_nsec -= (uvp)->tv_nsec; \ if ((vvp)->tv_nsec < 0) { \ (vvp)->tv_sec--; \ (vvp)->tv_nsec += 1000000000; \ } \ } while (0) /* Operations on timevals. */ #define timevalclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) #define timevalisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) #define timevalcmp(tvp, uvp, cmp) \ (((tvp)->tv_sec == (uvp)->tv_sec) ? \ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ ((tvp)->tv_sec cmp (uvp)->tv_sec)) /* timevaladd and timevalsub are not inlined */ #endif /* _KERNEL */ #ifndef _KERNEL /* NetBSD/OpenBSD compatible interfaces */ #define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) #define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) #define timercmp(tvp, uvp, cmp) \ (((tvp)->tv_sec == (uvp)->tv_sec) ? \ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ ((tvp)->tv_sec cmp (uvp)->tv_sec)) #define timeradd(tvp, uvp, vvp) \ do { \ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ if ((vvp)->tv_usec >= 1000000) { \ (vvp)->tv_sec++; \ (vvp)->tv_usec -= 1000000; \ } \ } while (0) #define timersub(tvp, uvp, vvp) \ do { \ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ if ((vvp)->tv_usec < 0) { \ (vvp)->tv_sec--; \ (vvp)->tv_usec += 1000000; \ } \ } while (0) #endif /* * Names of the interval timers, and structure * defining a timer setting. */ #define ITIMER_REAL 0 #define ITIMER_VIRTUAL 1 #define ITIMER_PROF 2 struct itimerval { struct timeval it_interval; /* timer interval */ struct timeval it_value; /* current value */ }; /* * Getkerninfo clock information structure */ struct clockinfo { int hz; /* clock frequency */ int tick; /* micro-seconds per hz tick */ int spare; int stathz; /* statistics clock frequency */ int profhz; /* profiling clock frequency */ }; /* These macros are also in time.h. */ #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 0 #define CLOCK_VIRTUAL 1 #define CLOCK_PROF 2 #define CLOCK_MONOTONIC 4 #define CLOCK_UPTIME 5 /* FreeBSD-specific. */ #define CLOCK_UPTIME_PRECISE 7 /* FreeBSD-specific. */ #define CLOCK_UPTIME_FAST 8 /* FreeBSD-specific. */ #define CLOCK_REALTIME_PRECISE 9 /* FreeBSD-specific. */ #define CLOCK_REALTIME_FAST 10 /* FreeBSD-specific. */ #define CLOCK_MONOTONIC_PRECISE 11 /* FreeBSD-specific. */ #define CLOCK_MONOTONIC_FAST 12 /* FreeBSD-specific. */ #define CLOCK_SECOND 13 /* FreeBSD-specific. */ #define CLOCK_THREAD_CPUTIME_ID 14 #define CLOCK_PROCESS_CPUTIME_ID 15 #endif #ifndef TIMER_ABSTIME #define TIMER_RELTIME 0x0 /* relative timer */ #define TIMER_ABSTIME 0x1 /* absolute timer */ #endif #if __BSD_VISIBLE #define CPUCLOCK_WHICH_PID 0 #define CPUCLOCK_WHICH_TID 1 #endif #ifdef _KERNEL /* * Kernel to clock driver interface. */ void inittodr(time_t base); void resettodr(void); extern volatile time_t time_second; extern volatile time_t time_uptime; extern struct bintime tc_tick_bt; extern sbintime_t tc_tick_sbt; extern struct bintime tick_bt; extern sbintime_t tick_sbt; extern int tc_precexp; extern int tc_timepercentage; extern struct bintime bt_timethreshold; extern struct bintime bt_tickthreshold; extern sbintime_t sbt_timethreshold; extern sbintime_t sbt_tickthreshold; extern volatile int rtc_generation; /* * Functions for looking at our clock: [get]{bin,nano,micro}[up]time() * * Functions without the "get" prefix returns the best timestamp * we can produce in the given format. * * "bin" == struct bintime == seconds + 64 bit fraction of seconds. * "nano" == struct timespec == seconds + nanoseconds. * "micro" == struct timeval == seconds + microseconds. * * Functions containing "up" returns time relative to boot and * should be used for calculating time intervals. * * Functions without "up" returns UTC time. * * Functions with the "get" prefix returns a less precise result * much faster than the functions without "get" prefix and should * be used where a precision of 1/hz seconds is acceptable or where * performance is priority. (NB: "precision", _not_ "resolution" !) */ void binuptime(struct bintime *bt); void nanouptime(struct timespec *tsp); void microuptime(struct timeval *tvp); static __inline sbintime_t sbinuptime(void) { struct bintime _bt; binuptime(&_bt); return (bttosbt(_bt)); } void bintime(struct bintime *bt); void nanotime(struct timespec *tsp); void microtime(struct timeval *tvp); void getbinuptime(struct bintime *bt); void getnanouptime(struct timespec *tsp); void getmicrouptime(struct timeval *tvp); static __inline sbintime_t getsbinuptime(void) { struct bintime _bt; getbinuptime(&_bt); return (bttosbt(_bt)); } void getbintime(struct bintime *bt); void getnanotime(struct timespec *tsp); void getmicrotime(struct timeval *tvp); void getboottime(struct timeval *boottime); void getboottimebin(struct bintime *boottimebin); /* Other functions */ int itimerdecr(struct itimerval *itp, int usec); int itimerfix(struct timeval *tv); int ppsratecheck(struct timeval *, int *, int); int ratecheck(struct timeval *, const struct timeval *); void timevaladd(struct timeval *t1, const struct timeval *t2); void timevalsub(struct timeval *t1, const struct timeval *t2); int tvtohz(struct timeval *tv); #define TC_DEFAULTPERC 5 #define BT2FREQ(bt) \ (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \ ((bt)->frac >> 1)) #define SBT2FREQ(sbt) ((SBT_1S + ((sbt) >> 1)) / (sbt)) #define FREQ2BT(freq, bt) \ { \ (bt)->sec = 0; \ (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \ } #define TIMESEL(sbt, sbt2) \ (((sbt2) >= sbt_timethreshold) ? \ ((*(sbt) = getsbinuptime()), 1) : ((*(sbt) = sbinuptime()), 0)) #else /* !_KERNEL */ #include #include #include __BEGIN_DECLS int setitimer(int, const struct itimerval *, struct itimerval *); int utimes(const char *, const struct timeval *); #if __BSD_VISIBLE int adjtime(const struct timeval *, struct timeval *); int clock_getcpuclockid2(id_t, int, clockid_t *); int futimes(int, const struct timeval *); int futimesat(int, const char *, const struct timeval [2]); int lutimes(const char *, const struct timeval *); int settimeofday(const struct timeval *, const struct timezone *); #endif #if __XSI_VISIBLE int getitimer(int, struct itimerval *); int gettimeofday(struct timeval *, struct timezone *); #endif __END_DECLS #endif /* !_KERNEL */ #endif /* !_SYS_TIME_H_ */