From: kettenis Date: Tue, 4 May 2021 16:38:06 +0000 (+0000) Subject: The clock on RISC-V is architectural, so we really don't need the X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=420b129f941aa8cb4634bcb1a5b42b47767b6e06;p=openbsd The clock on RISC-V is architectural, so we really don't need the whole abstraction layer to support multiple timers. And we don't really need a separate driver. Replace timer(4) with code based on the powerpc64 implementation of the randomized statclock code. Fixes hangs seen on real hardware. ok jsg@, drahn@ --- diff --git a/sys/arch/riscv64/conf/GENERIC b/sys/arch/riscv64/conf/GENERIC index ee9f0fca463..4014ac7349b 100644 --- a/sys/arch/riscv64/conf/GENERIC +++ b/sys/arch/riscv64/conf/GENERIC @@ -29,7 +29,6 @@ mainbus0 at root # cpu0 cpu0 at mainbus0 -timer0 at cpu0 intc0 at cpu0 # NS16550 compatible serial ports diff --git a/sys/arch/riscv64/conf/RAMDISK b/sys/arch/riscv64/conf/RAMDISK index 7955b94ed5e..4c6eb617020 100644 --- a/sys/arch/riscv64/conf/RAMDISK +++ b/sys/arch/riscv64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.5 2021/04/25 02:48:00 jsg Exp $ +# $OpenBSD: RAMDISK,v 1.6 2021/05/04 16:38:06 kettenis Exp $ # # GENERIC machine description file # @@ -48,7 +48,6 @@ mainbus0 at root # cpu0 cpu0 at mainbus0 -timer0 at cpu0 intc0 at cpu0 # NS16550 compatible serial ports diff --git a/sys/arch/riscv64/conf/files.riscv64 b/sys/arch/riscv64/conf/files.riscv64 index 6111eec5a5d..2294c06354b 100644 --- a/sys/arch/riscv64/conf/files.riscv64 +++ b/sys/arch/riscv64/conf/files.riscv64 @@ -12,6 +12,7 @@ file arch/riscv64/riscv64/autoconf.c file arch/riscv64/riscv64/ast.c file arch/riscv64/riscv64/bus_space.c file arch/riscv64/riscv64/bus_dma.c +file arch/riscv64/riscv64/clock.c file arch/riscv64/riscv64/conf.c file arch/riscv64/riscv64/disksubr.c disk file arch/riscv64/riscv64/locore.S @@ -60,13 +61,6 @@ device cpu attach cpu at mainbus file arch/riscv64/riscv64/cpu.c cpu -# -# timer -# -device timer -attach timer at cpu -file arch/riscv64/dev/timer.c timer - # # HART-specific interrupt controller # diff --git a/sys/arch/riscv64/dev/mainbus.c b/sys/arch/riscv64/dev/mainbus.c index a43d437fff8..a6e0c32ff81 100644 --- a/sys/arch/riscv64/dev/mainbus.c +++ b/sys/arch/riscv64/dev/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.4 2021/05/04 12:46:28 kettenis Exp $ */ +/* $OpenBSD: mainbus.c,v 1.5 2021/05/04 16:38:06 kettenis Exp $ */ /* * Copyright (c) 2016 Patrick Wildt * Copyright (c) 2017 Mark Kettenis @@ -91,8 +91,6 @@ mainbus_match(struct device *parent, void *cfdata, void *aux) return (1); } -void riscv_timer_init(void); - void mainbus_attach(struct device *parent, struct device *self, void *aux) { @@ -101,7 +99,6 @@ mainbus_attach(struct device *parent, struct device *self, void *aux) int node, len; riscv_intr_init_fdt(); - riscv_timer_init(); sc->sc_node = OF_peer(0); sc->sc_iot = &riscv64_bs_tag; diff --git a/sys/arch/riscv64/dev/timer.c b/sys/arch/riscv64/dev/timer.c deleted file mode 100644 index 849b0c91592..00000000000 --- a/sys/arch/riscv64/dev/timer.c +++ /dev/null @@ -1,368 +0,0 @@ -/*- - * Copyright (c) 2015-2017 Ruslan Bukin - * All rights reserved. - * - * Portions of this software were developed by SRI International and the - * University of Cambridge Computer Laboratory under DARPA/AFRL contract - * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. - * - * Portions of this software were developed by the University of Cambridge - * Computer Laboratory as part of the CTSRD Project, with support from the - * UK Higher Education Innovation Fund (HEIF). - * - * 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. - */ - -/* - * RISC-V Timer - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "riscv_cpu_intc.h" - -#include -#include - - -#define TIMER_COUNTS 0x00 -#define TIMER_MTIMECMP(cpu) (cpu * 8) -#define TIMER_FREQUENCY 10 * 1000 * 1000 /* RISC-V time clock */ - -unsigned riscv_timer_get_timecount(struct timecounter *); - -static struct timecounter riscv_timer_timecount = { - .tc_name = "RISC-V Timecounter", - .tc_get_timecount = riscv_timer_get_timecount, - .tc_poll_pps = NULL, - .tc_counter_mask = ~0u, - .tc_frequency = 0, - .tc_quality = 1000, - .tc_priv = NULL, -}; - -struct riscv_timer_pcpu_softc { - uint64_t pc_nexttickevent; - uint64_t pc_nextstatevent; - u_int32_t pc_ticks_err_sum; -}; - -struct riscv_timer_softc { - struct device sc_dev; - int sc_node; - - struct riscv_timer_pcpu_softc sc_pstat[MAXCPUS]; - - u_int32_t sc_ticks_err_cnt; - u_int32_t sc_ticks_per_second; // sc_clkfreq - u_int32_t sc_ticks_per_intr; - u_int32_t sc_statvar; - u_int32_t sc_statmin; - - void *sc_ih; -}; - -static struct riscv_timer_softc *riscv_timer_sc = NULL; - -int riscv_timer_get_freq(); -int riscv_timer_match(struct device *, void *, void *); -void riscv_timer_attach(struct device *, struct device *, void *); -int riscv_timer_intr(void *); -void riscv_timer_cpu_initclocks(); -void riscv_timer_delay(u_int); -void riscv_timer_setstatclockrate(int); -void riscv_timer_startclock(); - -struct cfattach timer_ca = { - sizeof (struct riscv_timer_softc), riscv_timer_match, - riscv_timer_attach -}; - -struct cfdriver timer_cd = { - NULL, "timer", DV_DULL -}; - -static inline uint64_t -get_cycles() -{ - return (rdtime()); -} - -long -get_counts(struct riscv_timer_softc *sc) -{ - uint64_t counts; - - counts = get_cycles(); - - return (counts); -} - -unsigned -riscv_timer_get_timecount(struct timecounter *tc) -{ - struct riscv_timer_softc *sc; - - sc = tc->tc_priv; - - return (get_counts(sc)); -} - -int -riscv_timer_get_freq() -{ - int node, len; - - node = OF_finddevice("/cpus"); - if (node == -1) { - printf("Can't find cpus node.\n"); - return (0); - } - - len = OF_getproplen(node, "timebase-frequency"); - if (len != 4) { - printf("Can't find timebase-frequency property.\n"); - return (0); - } - - return OF_getpropint(node, "timebase-frequency", 0); -} - -int -riscv_timer_match(struct device *parent, void *cfdata, void *aux) -{ - if (riscv_timer_sc) //already attached - return 0; - - int node; - // struct fdt_attach_args *fa = (struct fdt_attach_args *)aux; - - /* - * return 1 if: - * we can find valid "timebase-frequency" property from cpus - */ - if ( (node = OF_finddevice("/cpus")) == 0) - return 0; - - return (OF_getproplen(node, "timebase-frequency") == 4);//32bit uint -} - -void -riscv_timer_attach(struct device *parent, struct device *self, void *aux) -{ - struct riscv_timer_softc *sc = (struct riscv_timer_softc *)self; - - if (riscv_timer_sc)/* already attached */ - return; - - sc->sc_ticks_per_second = riscv_timer_get_freq(); - if (sc->sc_ticks_per_second == 0) { - printf("Failed to resolve RISC-V Timer timebase\n"); - return; - } - printf(": tick rate %d KHz\n", sc->sc_ticks_per_second/1000); - - riscv_timer_sc = sc; - stathz = 0; - - riscv_clock_register(riscv_timer_cpu_initclocks, riscv_timer_delay, - riscv_timer_setstatclockrate, riscv_timer_startclock); - - riscv_timer_timecount.tc_frequency = sc->sc_ticks_per_second; - riscv_timer_timecount.tc_priv = sc; - - tc_init(&riscv_timer_timecount); -} - - -int timer_mindelta = 0; /* what should this be? */ -int -riscv_timer_intr(void *frame) -{ - struct riscv_timer_softc *sc; - uint64_t next, now, newnow; - int timermissed = 0; - u_int new_hz = 100; - int s; - -#ifdef DEBUG_TIMER - printf("RISC-V Timer Interrupt\n"); -#endif - - sc = riscv_timer_sc; - - s = splclock(); - - if (s < IPL_CLOCK) - hardclock(frame); - - // XXX should base timer interval from the expected - // time of expiration, not 'now' - now = get_cycles(); - next = now + ((sc->sc_ticks_per_second / new_hz)); - - do { - newnow = get_cycles(); - if (next < (newnow + timer_mindelta)) { - /* slowly scale up miss timer. */ - if (timermissed > 1) - timer_mindelta ++; - } - next = newnow + timer_mindelta; - sbi_set_timer(next); - csr_set(sip, SIE_STIE); - - /* re-read current time to verif - * time hasn't been set into the past - */ - - newnow = get_cycles(); - /* if we missed more than once, increment the min period */ - timermissed++; - } while (next <= newnow); - - splx(s); - return (1); // Handled -} - -void -riscv_timer_cpu_initclocks() -{ - struct riscv_timer_softc *sc = timer_cd.cd_devs[0]; - struct riscv_timer_pcpu_softc *pc = - &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; - uint64_t next; - - stathz = hz; - profhz = hz * 10; - - riscv_timer_setstatclockrate(stathz); - - sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz; - sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz; - pc->pc_ticks_err_sum = 0; - - /* configure virtual timer interrupt */ - sc->sc_ih = riscv_intc_intr_establish(IRQ_TIMER_SUPERVISOR, 0, - riscv_timer_intr, NULL, "timer"); - - next = get_cycles() + sc->sc_ticks_per_intr; - pc->pc_nexttickevent = pc->pc_nextstatevent = next; - - sbi_set_timer(next); - csr_set(sie, SIE_STIE); -} - -void -riscv_timer_delay(u_int usec) -{ - int64_t counts, counts_per_usec; - uint64_t first, last; - - /* - * Check the timers are setup, if not just - * use a for loop for the meantime - */ - if (riscv_timer_sc == NULL) { - for (; usec > 0; usec--) - for (counts = 200; counts > 0; counts--) - /* - * Prevent the compiler from optimizing - * out the loop - */ - cpufunc_nullop(); - return; - } - - /* Get the number of times to count */ - counts_per_usec = ((riscv_timer_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 = get_counts(riscv_timer_sc); - - while (counts > 0) { - last = get_counts(riscv_timer_sc); - counts -= (int64_t)(last - first); - first = last; - } -} - -void -riscv_timer_setstatclockrate(int newhz) -{ - /* dummy: clockrate on riscv is fixed*/ -} - -/* is only called from secondary cpu */ -void -riscv_timer_startclock() -{ - struct riscv_timer_softc *sc = timer_cd.cd_devs[0]; - struct riscv_timer_pcpu_softc *pc = - &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; - uint64_t nextevent; - - nextevent = get_cycles() + sc->sc_ticks_per_intr; - pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent; - - riscv_intr_route(sc->sc_ih, 1, curcpu()); - - sbi_set_timer(nextevent); - csr_set(sie, SIE_STIE); -} - -/* - * called at early mainbus_attach, to provide delay func - * before timer and interrupt is ready - */ -void -riscv_timer_init(void) -{ - uint64_t cntfrq = 0; - - cntfrq = riscv_timer_get_freq(); - - if (cntfrq != 0) { - riscv_clock_register(NULL, riscv_timer_delay, NULL, NULL); - } -} diff --git a/sys/arch/riscv64/dev/timer.h b/sys/arch/riscv64/dev/timer.h deleted file mode 100644 index bab1a36b610..00000000000 --- a/sys/arch/riscv64/dev/timer.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2020 Mars Li - * - * 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 ``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. - * - */ - -#ifndef _MACHINE_TIMER_H_ -#define _MACHINE_TIMER_H_ - -int riscv_timer_match(struct device *, void *, void *); - -#endif /* _MACHINE_TIMER_H_ */ diff --git a/sys/arch/riscv64/include/cpu.h b/sys/arch/riscv64/include/cpu.h index cdcfe692f0f..db001abf4c6 100644 --- a/sys/arch/riscv64/include/cpu.h +++ b/sys/arch/riscv64/include/cpu.h @@ -95,6 +95,11 @@ struct cpu_info { u_int32_t ci_ctrl; /* The CPU control register */ + uint64_t ci_lasttb; + uint64_t ci_nexttimerevent; + uint64_t ci_nextstatevent; + int ci_statspending; + uint32_t ci_cpl; uint32_t ci_ipending; uint32_t ci_idepth; diff --git a/sys/arch/riscv64/riscv64/clock.c b/sys/arch/riscv64/riscv64/clock.c new file mode 100644 index 00000000000..9ee3bb77876 --- /dev/null +++ b/sys/arch/riscv64/riscv64/clock.c @@ -0,0 +1,195 @@ +/* $OpenBSD: clock.c,v 1.1 2021/05/04 16:38:06 kettenis Exp $ */ + +/* + * Copyright (c) 2020 Mark Kettenis + * Copyright (c) 2003 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +extern uint32_t tb_freq; /* machdep.c */ + +uint64_t tick_increment; +uint64_t statmin; +uint32_t statvar; + +struct evcount clock_count; +struct evcount stat_count; + +u_int tb_get_timecount(struct timecounter *); + +static struct timecounter tb_timecounter = { + .tc_get_timecount = tb_get_timecount, + .tc_poll_pps = NULL, + .tc_counter_mask = 0xffffffff, + .tc_frequency = 0, + .tc_name = "tb", + .tc_quality = 0, + .tc_priv = NULL, +}; + +void cpu_startclock(void); +int clock_intr(void *); + +u_int +tb_get_timecount(struct timecounter *tc) +{ + return rdtime(); +} + +void +cpu_initclocks(void) +{ + tick_increment = tb_freq / hz; + + stathz = 100; + profhz = 1000; /* must be a multiple of stathz */ + + setstatclockrate(stathz); + + riscv_intc_intr_establish(IRQ_TIMER_SUPERVISOR, 0, + clock_intr, NULL, NULL); + + evcount_attach(&clock_count, "clock", NULL); + evcount_attach(&stat_count, "stat", NULL); + + cpu_startclock(); + + tb_timecounter.tc_frequency = tb_freq; + tc_init(&tb_timecounter); +} + +void +cpu_startclock(void) +{ + struct cpu_info *ci = curcpu(); + uint64_t nextevent; + + ci->ci_lasttb = rdtime(); + ci->ci_nexttimerevent = ci->ci_lasttb + tick_increment; + nextevent = ci->ci_nextstatevent = ci->ci_nexttimerevent; + + sbi_set_timer(nextevent); + csr_set(sie, SIE_STIE); +} + +int +clock_intr(void *frame) +{ + struct cpu_info *ci = curcpu(); + uint64_t tb, prevtb; + uint64_t nextevent; + uint32_t r; + int nstats; + int s; + + /* + * Based on the actual time delay since the last clock interrupt, + * we arrange for earlier interrupt next time. + */ + + tb = rdtime(); + + while (ci->ci_nexttimerevent <= tb) + ci->ci_nexttimerevent += tick_increment; + + prevtb = ci->ci_nexttimerevent - tick_increment; + + for (nstats = 0; ci->ci_nextstatevent <= tb; nstats++) { + do { + r = random() & (statvar - 1); + } while (r == 0); /* random == 0 not allowed */ + ci->ci_nextstatevent += statmin + r; + } + stat_count.ec_count += nstats; + + if (ci->ci_nexttimerevent < ci->ci_nextstatevent) + nextevent = ci->ci_nexttimerevent; + else + nextevent = ci->ci_nextstatevent; + + sbi_set_timer(nextevent); + + if (ci->ci_cpl >= IPL_CLOCK) { + ci->ci_statspending += nstats; + } else { + nstats += ci->ci_statspending; + ci->ci_statspending = 0; + + s = splclock(); + intr_enable(); + + /* + * Do standard timer interrupt stuff. + */ + while (ci->ci_lasttb < prevtb) { + ci->ci_lasttb += tick_increment; + clock_count.ec_count++; + hardclock((struct clockframe *)frame); + } + + while (nstats-- > 0) + statclock((struct clockframe *)frame); + + intr_disable(); + splx(s); + } + + return 0; +} + +void +setstatclockrate(int newhz) +{ + uint64_t stat_increment; + uint64_t min_increment; + uint32_t var; + u_long msr; + + msr = intr_disable(); + + stat_increment = tb_freq / newhz; + var = 0x40000000; /* really big power of two */ + /* Find largest 2^n which is nearly smaller than statint/2. */ + min_increment = stat_increment / 2 + 100; + while (var > min_increment) + var >>= 1; + + /* Not atomic, but we can probably live with that. */ + statmin = stat_increment - (var >> 1); + statvar = var; + + intr_restore(msr); +} + +void +delay(u_int us) +{ + uint64_t tb; + + tb = rdtime(); + tb += (us * tb_freq + 999999) / 1000000; + while (tb > rdtime()) + continue; +} diff --git a/sys/arch/riscv64/riscv64/cpu.c b/sys/arch/riscv64/riscv64/cpu.c index 10516dd6114..89b49fe9eca 100644 --- a/sys/arch/riscv64/riscv64/cpu.c +++ b/sys/arch/riscv64/riscv64/cpu.c @@ -23,7 +23,6 @@ #include #include -#include "../dev/timer.h" #include #include @@ -158,15 +157,6 @@ cpu_attach(struct device *parent, struct device *dev, void *aux) cpu_cpuspeed = cpu_clockspeed; } - /* - * attach cpu-embedded timer - * Trick: timer has no fdt node to match, - * riscv_timer_match will always return 1 at first call, - * and return 0 for all following calls, - * therefore, must attach timer before any node - */ - config_found_sm(dev, NULL, NULL, riscv_timer_match); - /* * attach cpu's children node, so far there is only the * cpu-embedded interrupt controller diff --git a/sys/arch/riscv64/riscv64/intr.c b/sys/arch/riscv64/riscv64/intr.c index 639cbe6e66c..7b605f83034 100644 --- a/sys/arch/riscv64/riscv64/intr.c +++ b/sys/arch/riscv64/riscv64/intr.c @@ -516,81 +516,6 @@ riscv_splassert_check(int wantipl, const char *func) } #endif -/* - ********* timer interrupt relevant ************** - */ - -void riscv_dflt_delay(u_int usecs); - -struct { - void (*delay)(u_int); - void (*initclocks)(void); - void (*setstatclockrate)(int); - void (*mpstartclock)(void); -} riscv_clock_func = { - riscv_dflt_delay, - NULL, - NULL, - NULL -}; - -void -riscv_clock_register(void (*initclock)(void), void (*delay)(u_int), - void (*statclock)(int), void(*mpstartclock)(void)) -{ - if (riscv_clock_func.initclocks) - return; - - riscv_clock_func.initclocks = initclock; - riscv_clock_func.delay = delay; - riscv_clock_func.setstatclockrate = statclock; - riscv_clock_func.mpstartclock = mpstartclock; -} - -void -delay(u_int usec) -{ - riscv_clock_func.delay(usec); -} - -void -cpu_initclocks(void) -{ - if (riscv_clock_func.initclocks == NULL) - panic("initclocks function not initialized yet"); - - riscv_clock_func.initclocks(); -} - -void -cpu_startclock(void) -{ - if (riscv_clock_func.mpstartclock == NULL) - panic("startclock function not initialized yet"); - - riscv_clock_func.mpstartclock(); -} - -void -riscv_dflt_delay(u_int usecs) -{ - int j; - /* BAH - there is no good way to make this close */ - /* but this isn't supposed to be used after the real clock attaches */ - for (; usecs > 0; usecs--) - for (j = 100; j > 0; j--) - ; -} - -void -setstatclockrate(int new) -{ - if (riscv_clock_func.setstatclockrate == NULL) { - panic("riscv_clock_func.setstatclockrate not initialized"); - } - riscv_clock_func.setstatclockrate(new); -} - void intr_barrier(void *ih) { diff --git a/sys/arch/riscv64/riscv64/machdep.c b/sys/arch/riscv64/riscv64/machdep.c index 7fae71ce895..8a971c32451 100644 --- a/sys/arch/riscv64/riscv64/machdep.c +++ b/sys/arch/riscv64/riscv64/machdep.c @@ -97,6 +97,8 @@ uint32_t boot_hart; /* The hart we booted on. */ struct cpu_info cpu_info_primary; struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary }; +uint32_t tb_freq = 1000000; + struct fdt_reg memreg[VM_PHYSSEG_MAX]; int nmemreg; @@ -561,6 +563,16 @@ initriscv(struct riscv_bootparams *rbp) struct fdt_reg reg; void *node; + node = fdt_find_node("/cpus"); + if (node != NULL) { + char *prop; + int len; + + len = fdt_node_property(node, "timebase-frequency", &prop); + if (len == sizeof(tb_freq)) + tb_freq = bemtoh32((uint32_t *)prop); + } + node = fdt_find_node("/chosen"); if (node != NULL) { char *prop;