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/clock.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2003-2009 RMI Corporation
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of RMI Corporation, nor the names of its contributors,
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * RMI_BSD */
   30 
   31 #include <sys/cdefs.h>          /* RCS ID & Copyright macro defns */
   32 
   33 #include <sys/param.h>
   34 #include <sys/kernel.h>
   35 #include <sys/lock.h>
   36 #include <sys/mutex.h>
   37 #include <sys/queue.h>
   38 #include <sys/smp.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/systm.h>
   41 #include <sys/timetc.h>
   42 
   43 #include <sys/module.h>
   44 #include <sys/stdint.h>
   45 
   46 #include <sys/bus.h>
   47 #include <sys/rman.h>
   48 #include <sys/systm.h>
   49 #include <sys/clock.h>
   50 
   51 #include <machine/clock.h>
   52 #include <machine/md_var.h>
   53 #include <machine/hwfunc.h>
   54 #include <machine/intr_machdep.h>
   55 
   56 #include <mips/rmi/iomap.h>
   57 #include <mips/rmi/clock.h>
   58 #include <mips/rmi/interrupt.h>
   59 #include <mips/rmi/pic.h>
   60 #include <mips/rmi/shared_structs.h>
   61 
   62 #ifdef XLR_PERFMON
   63 #include <mips/rmi/perfmon.h>
   64 #endif
   65 
   66 uint64_t counter_freq;
   67 uint64_t cycles_per_tick;
   68 uint64_t cycles_per_usec;
   69 uint64_t cycles_per_sec;
   70 uint64_t cycles_per_hz;
   71 
   72 u_int32_t counter_upper = 0;
   73 u_int32_t counter_lower_last = 0;
   74 
   75 #define STAT_PROF_CLOCK_SCALE_FACTOR 8
   76 
   77 static int scale_factor;
   78 static int count_scale_factor[32];
   79 
   80 uint64_t
   81 platform_get_frequency()
   82 {
   83         return XLR_PIC_HZ;
   84 }
   85 
   86 void
   87 mips_timer_early_init(uint64_t clock_hz)
   88 {
   89         /* Initialize clock early so that we can use DELAY sooner */
   90         counter_freq = clock_hz;
   91         cycles_per_usec = (clock_hz / (1000 * 1000));
   92 
   93 }
   94 
   95 /*
   96 * count_compare_clockhandler:
   97 *
   98 * Handle the clock interrupt when count becomes equal to
   99 * compare.
  100 */
  101 int
  102 count_compare_clockhandler(struct trapframe *tf)
  103 {
  104         int cpu = PCPU_GET(cpuid);
  105         uint32_t cycles;
  106 
  107         critical_enter();
  108 
  109         if (cpu == 0) {
  110                 mips_wr_compare(0);
  111         } else {
  112                 count_scale_factor[cpu]++;
  113                 cycles = mips_rd_count();
  114                 cycles += XLR_CPU_HZ / hz;
  115                 mips_wr_compare(cycles);
  116 
  117                 hardclock_cpu(USERMODE(tf->sr));
  118                 if (count_scale_factor[cpu] == STAT_PROF_CLOCK_SCALE_FACTOR) {
  119                         statclock(USERMODE(tf->sr));
  120                         if (profprocs != 0) {
  121                                 profclock(USERMODE(tf->sr), tf->pc);
  122                         }
  123                         count_scale_factor[cpu] = 0;
  124                 }
  125                 /* If needed , handle count compare tick skew here */
  126         }
  127 
  128         critical_exit();
  129         return (FILTER_HANDLED);
  130 }
  131 
  132 int
  133 pic_hardclockhandler(struct trapframe *tf)
  134 {
  135         int cpu = PCPU_GET(cpuid);
  136 
  137         critical_enter();
  138 
  139         if (cpu == 0) {
  140                 scale_factor++;
  141                 hardclock(USERMODE(tf->sr), tf->pc);
  142                 if (scale_factor == STAT_PROF_CLOCK_SCALE_FACTOR) {
  143                         statclock(USERMODE(tf->sr));
  144                         if (profprocs != 0) {
  145                                 profclock(USERMODE(tf->sr), tf->pc);
  146                         }
  147                         scale_factor = 0;
  148                 }
  149 #ifdef XLR_PERFMON
  150                 if (xlr_perfmon_started)
  151                         xlr_perfmon_clockhandler();
  152 #endif
  153 
  154         } else {
  155                 /* If needed , handle count compare tick skew here */
  156         }
  157         critical_exit();
  158         return (FILTER_HANDLED);
  159 }
  160 
  161 int
  162 pic_timecounthandler(struct trapframe *tf)
  163 {
  164         return (FILTER_HANDLED);
  165 }
  166 
  167 void
  168 rmi_early_counter_init()
  169 {
  170         int cpu = PCPU_GET(cpuid);
  171         xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
  172 
  173         /*
  174          * We do this to get the PIC time counter running right after system
  175          * start. Otherwise the DELAY() function will not be able to work
  176          * since it won't have a TC to read.
  177          */
  178         xlr_write_reg(mmio, PIC_TIMER_6_MAXVAL_0, (0xffffffff & 0xffffffff));
  179         xlr_write_reg(mmio, PIC_TIMER_6_MAXVAL_1, (0xffffffff & 0xffffffff));
  180         xlr_write_reg(mmio, PIC_IRT_0_TIMER_6, (1 << cpu));
  181         xlr_write_reg(mmio, PIC_IRT_1_TIMER_6, (1 << 31) | (0 << 30) | (1 << 6) | (PIC_TIMER_6_IRQ));
  182         pic_update_control(1 << (8 + 6));
  183 }
  184 
  185 void tick_init(void);
  186 
  187 void
  188 platform_initclocks(void)
  189 {
  190         int cpu = PCPU_GET(cpuid);
  191         void *cookie;
  192 
  193         /*
  194          * Note: Passing #3 as NULL ensures that clockhandler gets called
  195          * with trapframe
  196          */
  197         /* profiling/process accounting timer interrupt for non-zero cpus */
  198         cpu_establish_hardintr("compare",
  199             (driver_filter_t *) count_compare_clockhandler,
  200             NULL,
  201             NULL,
  202             IRQ_TIMER,
  203             INTR_TYPE_CLK | INTR_FAST, &cookie);
  204 
  205         /* timekeeping timer interrupt for cpu 0 */
  206         cpu_establish_hardintr("hardclk",
  207             (driver_filter_t *) pic_hardclockhandler,
  208             NULL,
  209             NULL,
  210             PIC_TIMER_7_IRQ,
  211             INTR_TYPE_CLK | INTR_FAST,
  212             &cookie);
  213 
  214         /* this is used by timecounter */
  215         cpu_establish_hardintr("timecount",
  216             (driver_filter_t *) pic_timecounthandler, NULL,
  217             NULL, PIC_TIMER_6_IRQ, INTR_TYPE_CLK | INTR_FAST,
  218             &cookie);
  219 
  220         if (cpu == 0) {
  221                 __uint64_t maxval = XLR_PIC_HZ / hz;
  222                 xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
  223 
  224                 stathz = hz / STAT_PROF_CLOCK_SCALE_FACTOR;
  225                 profhz = stathz;
  226 
  227                 /* Setup PIC Interrupt */
  228 
  229                 if (rmi_spin_mutex_safe)
  230                         mtx_lock_spin(&xlr_pic_lock);
  231                 xlr_write_reg(mmio, PIC_TIMER_7_MAXVAL_0, (maxval & 0xffffffff));       /* 0x100 + 7 */
  232                 xlr_write_reg(mmio, PIC_TIMER_7_MAXVAL_1, (maxval >> 32) & 0xffffffff); /* 0x110 + 7 */
  233                 /* 0x40 + 8 */
  234                 /* reg 40 is lower bits 31-0  and holds CPU mask */
  235                 xlr_write_reg(mmio, PIC_IRT_0_TIMER_7, (1 << cpu));
  236                 /* 0x80 + 8 */
  237                 /* Reg 80 is upper bits 63-32 and holds                              */
  238                 /* Valid   Edge    Local    IRQ */
  239                 xlr_write_reg(mmio, PIC_IRT_1_TIMER_7, (1 << 31) | (0 << 30) | (1 << 6) | (PIC_TIMER_7_IRQ));
  240                 pic_update_control(1 << (8 + 7));
  241 
  242                 xlr_write_reg(mmio, PIC_TIMER_6_MAXVAL_0, (0xffffffff & 0xffffffff));
  243                 xlr_write_reg(mmio, PIC_TIMER_6_MAXVAL_1, (0x0 & 0xffffffff));
  244                 xlr_write_reg(mmio, PIC_IRT_0_TIMER_6, (1 << cpu));
  245                 xlr_write_reg(mmio, PIC_IRT_1_TIMER_6, (1 << 31) | (0 << 30) | (1 << 6) | (PIC_TIMER_6_IRQ));
  246                 pic_update_control(1 << (8 + 6));
  247                 if (rmi_spin_mutex_safe)
  248                         mtx_unlock_spin(&xlr_pic_lock);
  249         } else {
  250                 /* Setup count-compare interrupt for vcpu[1-31] */
  251                 mips_wr_compare((xlr_boot1_info.cpu_frequency) / hz);
  252         }
  253         tick_init();
  254 }
  255 
  256 unsigned
  257 __attribute__((no_instrument_function))
  258 platform_get_timecount(struct timecounter *tc __unused)
  259 {
  260         xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
  261 
  262         return 0xffffffffU - xlr_read_reg(mmio, PIC_TIMER_6_COUNTER_0);
  263 }
  264 
  265 void
  266 DELAY(int n)
  267 {
  268         uint32_t cur, last, delta, usecs;
  269 
  270         /*
  271          * This works by polling the timer and counting the number of
  272          * microseconds that go by.
  273          */
  274         last = platform_get_timecount(NULL);
  275         delta = usecs = 0;
  276 
  277         while (n > usecs) {
  278                 cur = platform_get_timecount(NULL);
  279 
  280                 /* Check to see if the timer has wrapped around. */
  281                 if (cur < last)
  282                         delta += (cur + (cycles_per_hz - last));
  283                 else
  284                         delta += (cur - last);
  285 
  286                 last = cur;
  287 
  288                 if (delta >= cycles_per_usec) {
  289                         usecs += delta / cycles_per_usec;
  290                         delta %= cycles_per_usec;
  291                 }
  292         }
  293 }
  294 
  295 static
  296 uint64_t
  297 read_pic_counter(void)
  298 {
  299         xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
  300         uint32_t lower, upper;
  301         uint64_t tc;
  302 
  303         /*
  304          * Pull the value of the 64 bit counter which is stored in PIC
  305          * register 120+N and 130+N
  306          */
  307         upper = 0xffffffffU - xlr_read_reg(mmio, PIC_TIMER_6_COUNTER_1);
  308         lower = 0xffffffffU - xlr_read_reg(mmio, PIC_TIMER_6_COUNTER_0);
  309         tc = (((uint64_t) upper << 32) | (uint64_t) lower);
  310         return (tc);
  311 }
  312 
  313 extern struct timecounter counter_timecounter;
  314 
  315 void
  316 mips_timer_init_params(uint64_t platform_counter_freq, int double_count)
  317 {
  318 
  319         /*
  320          * XXX: Do not use printf here: uart code 8250 may use DELAY so this
  321          * function should  be called before cninit.
  322          */
  323         counter_freq = platform_counter_freq;
  324         /*
  325          * XXX: Some MIPS32 cores update the Count register only every two
  326          * pipeline cycles.
  327          */
  328         if (double_count != 0)
  329                 counter_freq /= 2;
  330 
  331         cycles_per_tick = counter_freq / 1000;
  332         cycles_per_hz = counter_freq / hz;
  333         cycles_per_usec = counter_freq / (1 * 1000 * 1000);
  334         cycles_per_sec = counter_freq;
  335 
  336         counter_timecounter.tc_frequency = counter_freq;
  337         printf("hz=%d cyl_per_hz:%jd cyl_per_usec:%jd freq:%jd cyl_per_hz:%jd cyl_per_sec:%jd\n",
  338             hz,
  339             cycles_per_tick,
  340             cycles_per_usec,
  341             counter_freq,
  342             cycles_per_hz,
  343             cycles_per_sec
  344             );
  345         set_cputicker(read_pic_counter, counter_freq, 1);
  346 }

Cache object: f628a4fdbcecb77bf20e97753031245a


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