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/mips/rmi/tick.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) 2006-2007 Bruce M. Simpson.
    3  * Copyright (c) 2003-2004 Juli Mallett.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *      notice, this list of conditions and the following 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 AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * Simple driver for the 32-bit interval counter built in to all
   30  * MIPS32 CPUs.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include "opt_cputype.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/bus.h>
   42 #include <sys/kernel.h>
   43 #include <sys/module.h>
   44 #include <sys/rman.h>
   45 #include <sys/power.h>
   46 #include <sys/smp.h>
   47 #include <sys/time.h>
   48 #include <sys/timetc.h>
   49 
   50 #include <machine/hwfunc.h>
   51 #include <machine/clock.h>
   52 #include <machine/locore.h>
   53 #include <machine/md_var.h>
   54 #include <machine/intr_machdep.h>
   55 #include <mips/rmi/interrupt.h>
   56 
   57 
   58 uint64_t counter_freq;
   59 
   60 struct timecounter *platform_timecounter;
   61 
   62 static uint64_t cycles_per_tick;
   63 static uint64_t cycles_per_usec;
   64 static uint64_t cycles_per_hz, cycles_per_stathz, cycles_per_profhz;
   65 
   66 struct clk_ticks {
   67         u_long hard_ticks;
   68         u_long stat_ticks;
   69         u_long prof_ticks;
   70         uint32_t compare_ticks;
   71         u_int32_t counter_upper;
   72         u_int32_t counter_lower_last;
   73 } __aligned(CACHE_LINE_SIZE);
   74 
   75 static struct clk_ticks pcpu_ticks[MAXCPU];
   76 
   77 /*
   78  * Device methods
   79  */
   80 static int clock_probe(device_t);
   81 static void clock_identify(driver_t *, device_t);
   82 static int clock_attach(device_t);
   83 static unsigned counter_get_timecount(struct timecounter *tc);
   84 
   85 static struct timecounter counter_timecounter = {
   86         counter_get_timecount,  /* get_timecount */
   87         0,                      /* no poll_pps */
   88         0xffffffffu,            /* counter_mask */
   89         0,                      /* frequency */
   90         "MIPS32",               /* name */
   91         800,                    /* quality (adjusted in code) */
   92 };
   93 
   94 void 
   95 mips_timer_early_init(uint64_t clock_hz)
   96 {
   97         /* Initialize clock early so that we can use DELAY sooner */
   98         counter_freq = clock_hz;
   99         cycles_per_usec = (clock_hz / (1000 * 1000));
  100 }
  101 
  102 void
  103 platform_initclocks(void)
  104 {
  105 
  106         tc_init(&counter_timecounter);
  107 
  108         if (platform_timecounter != NULL)
  109                 tc_init(platform_timecounter);
  110 }
  111 
  112 static uint64_t
  113 tick_ticker(void)
  114 {
  115         uint64_t ret;
  116         uint32_t ticktock;
  117         struct clk_ticks *cpu_ticks;
  118 
  119         cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)];
  120         ticktock = mips_rd_count();
  121         /*
  122          * XXX: get full time update logic from r210854
  123          */
  124         critical_enter();
  125         if (ticktock < cpu_ticks->counter_lower_last)
  126                 cpu_ticks->counter_upper++;
  127         cpu_ticks->counter_lower_last = ticktock;
  128         critical_exit();
  129 
  130         ret = ((uint64_t) cpu_ticks->counter_upper << 32) |
  131             cpu_ticks->counter_lower_last;
  132         return (ret);
  133 }
  134 
  135 void
  136 mips_timer_init_params(uint64_t platform_counter_freq, int double_count)
  137 {
  138 
  139         stathz = hz;
  140         profhz = hz;
  141 
  142         /*
  143          * XXX: Do not use printf here: uart code 8250 may use DELAY so this
  144          * function should  be called before cninit.
  145          */
  146         counter_freq = platform_counter_freq;
  147         /*
  148          * XXX: Some MIPS32 cores update the Count register only every two
  149          * pipeline cycles.
  150          * We know this because of status registers in CP0, make it automatic.
  151          */
  152         if (double_count != 0)
  153                 counter_freq /= 2;
  154 
  155         cycles_per_tick = counter_freq / 1000;
  156         cycles_per_hz = counter_freq / hz;
  157         cycles_per_stathz = counter_freq / stathz;
  158         cycles_per_profhz = counter_freq / profhz;
  159         cycles_per_usec = counter_freq / (1 * 1000 * 1000);
  160         
  161         counter_timecounter.tc_frequency = counter_freq;
  162         printf("hz=%d cyl_per_tick:%jd cyl_per_usec:%jd freq:%jd "
  163                "cyl_per_hz:%jd cyl_per_stathz:%jd cyl_per_profhz:%jd\n",
  164                hz,
  165                cycles_per_tick,
  166                cycles_per_usec,
  167                counter_freq,
  168                cycles_per_hz,
  169                cycles_per_stathz,
  170                cycles_per_profhz);
  171         set_cputicker(tick_ticker, counter_freq, 1);
  172 }
  173 
  174 static int
  175 sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS)
  176 {
  177         int error;
  178         uint64_t freq;
  179 
  180         if (counter_timecounter.tc_frequency == 0)
  181                 return (EOPNOTSUPP);
  182         freq = counter_freq;
  183         error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
  184         if (error == 0 && req->newptr != NULL) {
  185                 counter_freq = freq;
  186                 counter_timecounter.tc_frequency = counter_freq;
  187         }
  188         return (error);
  189 }
  190 
  191 SYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_QUAD | CTLFLAG_RW,
  192     0, sizeof(u_int), sysctl_machdep_counter_freq, "IU",
  193     "Timecounter frequency in Hz");
  194 
  195 static unsigned
  196 counter_get_timecount(struct timecounter *tc)
  197 {
  198 
  199         return (mips_rd_count());
  200 }
  201 
  202 
  203 void
  204 cpu_startprofclock(void)
  205 {
  206         /* nothing to do */
  207 }
  208 
  209 void
  210 cpu_stopprofclock(void)
  211 {
  212         /* nothing to do */
  213 }
  214 
  215 /*
  216  * Wait for about n microseconds (at least!).
  217  */
  218 void
  219 DELAY(int n)
  220 {
  221         uint32_t cur, last, delta, usecs;
  222 
  223         /*
  224          * This works by polling the timer and counting the number of
  225          * microseconds that go by.
  226          */
  227         last = mips_rd_count();
  228         delta = usecs = 0;
  229 
  230         while (n > usecs) {
  231                 cur = mips_rd_count();
  232 
  233                 /* Check to see if the timer has wrapped around. */
  234                 if (cur < last)
  235                         delta += cur + (0xffffffff - last) + 1;
  236                 else
  237                         delta += cur - last;
  238 
  239                 last = cur;
  240 
  241                 if (delta >= cycles_per_usec) {
  242                         usecs += delta / cycles_per_usec;
  243                         delta %= cycles_per_usec;
  244                 }
  245         }
  246 }
  247 
  248 /*
  249  * Device section of file below
  250  */
  251 static int
  252 clock_intr(void *arg)
  253 {
  254         struct clk_ticks *cpu_ticks;
  255         struct trapframe *tf;
  256         uint32_t count, compare, delta;
  257 
  258         cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)];
  259 
  260         /*
  261          * Set next clock edge.
  262          */
  263         count = mips_rd_count();
  264         compare = cpu_ticks->compare_ticks;
  265         cpu_ticks->compare_ticks = count + cycles_per_tick;
  266         mips_wr_compare(cpu_ticks->compare_ticks);
  267         critical_enter();
  268         if (count < cpu_ticks->counter_lower_last) {
  269                 cpu_ticks->counter_upper++;
  270         }
  271         cpu_ticks->counter_lower_last = count;
  272         /*
  273          * Magic.  Setting up with an arg of NULL means we get passed tf.
  274          */
  275         tf = (struct trapframe *)arg;
  276 
  277         delta = cycles_per_tick;
  278 
  279         /*
  280          * Account for the "lost time" between when the timer interrupt fired
  281          * and when 'clock_intr' actually started executing.
  282          */
  283         delta += count - compare;
  284 
  285         /*
  286          * If the COUNT and COMPARE registers are no longer in sync then make
  287          * up some reasonable value for the 'delta'.
  288          *
  289          * This could happen, for e.g., after we resume normal operations after
  290          * exiting the debugger.
  291          */
  292         if (delta > cycles_per_hz)
  293                 delta = cycles_per_hz;
  294 #ifdef KDTRACE_HOOKS
  295         /*
  296          * If the DTrace hooks are configured and a callback function
  297          * has been registered, then call it to process the high speed
  298          * timers.
  299          */
  300         int cpu = PCPU_GET(cpuid);
  301         if (cyclic_clock_func[cpu] != NULL)
  302                 (*cyclic_clock_func[cpu])(tf);
  303 #endif
  304         /* Fire hardclock at hz. */
  305         cpu_ticks->hard_ticks += delta;
  306         if (cpu_ticks->hard_ticks >= cycles_per_hz) {
  307                 cpu_ticks->hard_ticks -= cycles_per_hz;
  308                 if (PCPU_GET(cpuid) == 0)
  309                         hardclock(TRAPF_USERMODE(tf), tf->pc);
  310                 else
  311                         hardclock_cpu(TRAPF_USERMODE(tf));
  312         }
  313 
  314         /* Fire statclock at stathz. */
  315         cpu_ticks->stat_ticks += delta;
  316         if (cpu_ticks->stat_ticks >= cycles_per_stathz) {
  317                 cpu_ticks->stat_ticks -= cycles_per_stathz;
  318                 statclock(TRAPF_USERMODE(tf));
  319         }
  320 
  321         /* Fire profclock at profhz, but only when needed. */
  322         cpu_ticks->prof_ticks += delta;
  323         if (cpu_ticks->prof_ticks >= cycles_per_profhz) {
  324                 cpu_ticks->prof_ticks -= cycles_per_profhz;
  325                 if (profprocs != 0)
  326                         profclock(TRAPF_USERMODE(tf), tf->pc);
  327         }
  328         critical_exit();
  329         return (FILTER_HANDLED);
  330 }
  331 
  332 static int
  333 clock_probe(device_t dev)
  334 {
  335 
  336         if (device_get_unit(dev) != 0)
  337                 panic("can't attach more clocks");
  338 
  339         device_set_desc(dev, "Generic MIPS32 ticker");
  340         return (0);
  341 }
  342 
  343 static void
  344 clock_identify(driver_t * drv, device_t parent)
  345 {
  346 
  347         BUS_ADD_CHILD(parent, 0, "clock", 0);
  348 }
  349 
  350 static int
  351 clock_attach(device_t dev)
  352 {
  353 
  354         cpu_establish_hardintr("compare", clock_intr, NULL,
  355             NULL, IRQ_TIMER, INTR_TYPE_CLK, NULL);
  356         mips_wr_compare(mips_rd_count() + counter_freq / hz);
  357         return (0);
  358 }
  359 
  360 static device_method_t clock_methods[] = {
  361         /* Device interface */
  362         DEVMETHOD(device_probe, clock_probe),
  363         DEVMETHOD(device_identify, clock_identify),
  364         DEVMETHOD(device_attach, clock_attach),
  365         DEVMETHOD(device_detach, bus_generic_detach),
  366         DEVMETHOD(device_shutdown, bus_generic_shutdown),
  367 
  368         {0, 0}
  369 };
  370 
  371 static driver_t clock_driver = {
  372         "clock", clock_methods, 32
  373 };
  374 
  375 static devclass_t clock_devclass;
  376 
  377 DRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0);

Cache object: 3ea9899d33c15514e2c0dd68d44221fd


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