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/powerpc/powerpc/clock.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  * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
    5  * Copyright (C) 1995, 1996 TooLs GmbH.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by TooLs GmbH.
   19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   20  *    derived from this software without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  *
   33  *      $NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $
   34  */
   35 /*
   36  * Copyright (C) 2001 Benno Rice.
   37  * All rights reserved.
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
   49  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   50  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   51  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   53  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   54  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   55  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   56  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   57  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   58  */
   59 
   60 #include <sys/cdefs.h>
   61 __FBSDID("$FreeBSD$");
   62 
   63 #include <sys/param.h>
   64 #include <sys/systm.h>
   65 #include <sys/kernel.h>
   66 #include <sys/bus.h>
   67 #include <sys/interrupt.h>
   68 #include <sys/pcpu.h>
   69 #include <sys/sysctl.h>
   70 #include <sys/timeet.h>
   71 #include <sys/timetc.h>
   72 #include <sys/vdso.h>
   73 
   74 #include <dev/ofw/openfirm.h>
   75 
   76 #include <machine/clock.h>
   77 #include <machine/cpu.h>
   78 #include <machine/intr_machdep.h>
   79 #include <machine/md_var.h>
   80 #include <machine/smp.h>
   81 
   82 /*
   83  * Initially we assume a processor with a bus frequency of 12.5 MHz.
   84  */
   85 static int              initialized = 0;
   86 static uint64_t         ps_per_tick = 80000;
   87 static u_long           ticks_per_sec = 12500000;
   88 static u_long           *decr_counts[MAXCPU];
   89 
   90 static int              decr_et_start(struct eventtimer *et,
   91     sbintime_t first, sbintime_t period);
   92 static int              decr_et_stop(struct eventtimer *et);
   93 static timecounter_get_t        decr_get_timecount;
   94 static uint32_t decr_vdso_timehands(struct vdso_timehands *vdso_th,
   95     struct timecounter *tc);
   96 #ifdef COMPAT_FREEBSD32
   97 static uint32_t decr_vdso_timehands32(struct vdso_timehands32 *vdso_th32,
   98     struct timecounter *tc);
   99 #endif
  100 
  101 struct decr_state {
  102         int     mode;   /* 0 - off, 1 - periodic, 2 - one-shot. */
  103         int32_t div;    /* Periodic divisor. */
  104 };
  105 DPCPU_DEFINE_STATIC(struct decr_state, decr_state);
  106 
  107 static struct eventtimer        decr_et;
  108 static struct timecounter       decr_tc = {
  109         .tc_get_timecount =             decr_get_timecount,
  110         .tc_counter_mask =              ~0u,
  111         .tc_name =                      "timebase",
  112         .tc_quality =                   1000,
  113         .tc_fill_vdso_timehands =       decr_vdso_timehands,
  114 #ifdef COMPAT_FREEBSD32
  115         .tc_fill_vdso_timehands32 =     decr_vdso_timehands32,
  116 #endif
  117 };
  118 
  119 /*
  120  * Decrementer interrupt handler.
  121  */
  122 void
  123 decr_intr(struct trapframe *frame)
  124 {
  125         struct decr_state *s = DPCPU_PTR(decr_state);
  126         int             nticks = 0;
  127         int32_t         val;
  128 
  129         if (!initialized)
  130                 return;
  131 
  132         (*decr_counts[curcpu])++;
  133 
  134 #ifdef BOOKE
  135         /*
  136          * Interrupt handler must reset DIS to avoid getting another
  137          * interrupt once EE is enabled.
  138          */
  139         mtspr(SPR_TSR, TSR_DIS);
  140 #endif
  141 
  142         if (s->mode == 1) {
  143                 /*
  144                  * Based on the actual time delay since the last decrementer
  145                  * reload, we arrange for earlier interrupt next time.
  146                  */
  147                 __asm ("mfdec %0" : "=r"(val));
  148                 while (val < 0) {
  149                         val += s->div;
  150                         nticks++;
  151                 }
  152                 mtdec(val);
  153         } else if (s->mode == 2) {
  154                 nticks = 1;
  155                 decr_et_stop(NULL);
  156         } else if (s->mode == 0) {
  157                 /* Potemkin timer ran out without an event. Just reset it. */
  158                 decr_et_stop(NULL);
  159         }
  160 
  161         while (nticks-- > 0) {
  162                 if (decr_et.et_active)
  163                         decr_et.et_event_cb(&decr_et, decr_et.et_arg);
  164         }
  165 }
  166 
  167 void
  168 cpu_initclocks(void)
  169 {
  170 
  171         decr_tc_init();
  172         cpu_initclocks_bsp();
  173 }
  174 
  175 /*
  176  * BSP early initialization.
  177  */
  178 void
  179 decr_init(void)
  180 {
  181         struct cpuref cpu;
  182         char buf[32];
  183 
  184         /*
  185          * Check the BSP's timebase frequency. Sometimes we can't find the BSP,
  186          * so fall back to the first CPU in this case.
  187          */
  188         if (platform_smp_get_bsp(&cpu) != 0)
  189                 platform_smp_first_cpu(&cpu);
  190         ticks_per_sec = platform_timebase_freq(&cpu);
  191         ps_per_tick = 1000000000000 / ticks_per_sec;
  192 
  193         set_cputicker(mftb, ticks_per_sec, false);
  194         snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
  195         intrcnt_add(buf, &decr_counts[curcpu]);
  196         decr_et_stop(NULL);
  197         initialized = 1;
  198 }
  199 
  200 #ifdef SMP
  201 /*
  202  * AP early initialization.
  203  */
  204 void
  205 decr_ap_init(void)
  206 {
  207         char buf[32];
  208 
  209         snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu);
  210         intrcnt_add(buf, &decr_counts[curcpu]);
  211         decr_et_stop(NULL);
  212 }
  213 #endif
  214 
  215 /*
  216  * Final initialization.
  217  */
  218 void
  219 decr_tc_init(void)
  220 {
  221 
  222         decr_tc.tc_frequency = ticks_per_sec;
  223         tc_init(&decr_tc);
  224         decr_et.et_name = "decrementer";
  225         decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
  226             ET_FLAGS_PERCPU;
  227         decr_et.et_quality = 1000;
  228         decr_et.et_frequency = ticks_per_sec;
  229         decr_et.et_min_period = (0x00000002LLU << 32) / ticks_per_sec;
  230         decr_et.et_max_period = (0x7fffffffLLU << 32) / ticks_per_sec;
  231         decr_et.et_start = decr_et_start;
  232         decr_et.et_stop = decr_et_stop;
  233         decr_et.et_priv = NULL;
  234         et_register(&decr_et);
  235 }
  236 
  237 uint32_t
  238 decr_vdso_timehands(struct vdso_timehands *vdso_th, struct timecounter *tc)
  239 {
  240         vdso_th->th_algo = VDSO_TH_ALGO_PPC_TB;
  241         bzero(vdso_th->th_res, sizeof(vdso_th->th_res));
  242         return (initialized == 1);
  243 }
  244 
  245 #ifdef COMPAT_FREEBSD32
  246 uint32_t
  247 decr_vdso_timehands32(struct vdso_timehands32 *vdso_th32,
  248     struct timecounter *tc)
  249 {
  250         vdso_th32->th_algo = VDSO_TH_ALGO_PPC_TB;
  251         bzero(vdso_th32->th_res, sizeof(vdso_th32->th_res));
  252         return (initialized == 1);
  253 }
  254 #endif
  255 
  256 /*
  257  * Event timer start method.
  258  */
  259 static int
  260 decr_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
  261 {
  262         struct decr_state *s = DPCPU_PTR(decr_state);
  263         uint32_t fdiv;
  264 #ifdef BOOKE
  265         uint32_t tcr;
  266 #endif
  267 
  268         if (period != 0) {
  269                 s->mode = 1;
  270                 s->div = (decr_et.et_frequency * period) >> 32;
  271         } else {
  272                 s->mode = 2;
  273                 s->div = 0;
  274         }
  275         if (first != 0)
  276                 fdiv = (decr_et.et_frequency * first) >> 32;
  277         else
  278                 fdiv = s->div;
  279 
  280 #ifdef BOOKE
  281         tcr = mfspr(SPR_TCR);
  282         tcr |= TCR_DIE;
  283         if (s->mode == 1) {
  284                 mtspr(SPR_DECAR, s->div);
  285                 tcr |= TCR_ARE;
  286         } else
  287                 tcr &= ~TCR_ARE;
  288         mtdec(fdiv);
  289         mtspr(SPR_TCR, tcr);
  290 #else
  291         mtdec(fdiv);
  292 #endif
  293 
  294         return (0);
  295 }
  296 
  297 /*
  298  * Event timer stop method.
  299  */
  300 static int
  301 decr_et_stop(struct eventtimer *et)
  302 {
  303         struct decr_state *s = DPCPU_PTR(decr_state);
  304 #ifdef BOOKE
  305         uint32_t tcr;
  306 #endif
  307 
  308         s->mode = 0;
  309         s->div = 0x7fffffff;
  310 #ifdef BOOKE
  311         tcr = mfspr(SPR_TCR);
  312         tcr &= ~(TCR_DIE | TCR_ARE);
  313         mtspr(SPR_TCR, tcr);
  314 #else
  315         mtdec(s->div);
  316 #endif
  317         return (0);
  318 }
  319 
  320 /*
  321  * Timecounter get method.
  322  */
  323 static unsigned
  324 decr_get_timecount(struct timecounter *tc)
  325 {
  326         return (mftb());
  327 }
  328 
  329 /*
  330  * Wait for about n microseconds (at least!).
  331  */
  332 void
  333 DELAY(int n)
  334 {
  335         volatile u_quad_t       tb;
  336         u_quad_t                ttb;
  337 
  338         TSENTER();
  339         tb = mftb();
  340         ttb = tb + howmany((uint64_t)n * 1000000, ps_per_tick);
  341         nop_prio_vlow();
  342         while (tb < ttb)
  343                 tb = mftb();
  344         nop_prio_medium();
  345         TSEXIT();
  346 }

Cache object: 3ef3bc724948b4db655fba9f1c50eca8


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