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

Cache object: 2bee21307836644ebd4e578075b50057


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