linux/arch/arm/kernel/sched_clock.c
<<
>>
Prefs
   1/*
   2 * sched_clock.c: support for extending counters to full 64-bit ns counter
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8#include <linux/clocksource.h>
   9#include <linux/init.h>
  10#include <linux/jiffies.h>
  11#include <linux/kernel.h>
  12#include <linux/sched.h>
  13#include <linux/timer.h>
  14
  15#include <asm/sched_clock.h>
  16
  17static void sched_clock_poll(unsigned long wrap_ticks);
  18static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0);
  19static void (*sched_clock_update_fn)(void);
  20
  21static void sched_clock_poll(unsigned long wrap_ticks)
  22{
  23        mod_timer(&sched_clock_timer, round_jiffies(jiffies + wrap_ticks));
  24        sched_clock_update_fn();
  25}
  26
  27void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
  28        unsigned int clock_bits, unsigned long rate)
  29{
  30        unsigned long r, w;
  31        u64 res, wrap;
  32        char r_unit;
  33
  34        sched_clock_update_fn = update;
  35
  36        /* calculate the mult/shift to convert counter ticks to ns. */
  37        clocks_calc_mult_shift(&cd->mult, &cd->shift, rate, NSEC_PER_SEC, 0);
  38
  39        r = rate;
  40        if (r >= 4000000) {
  41                r /= 1000000;
  42                r_unit = 'M';
  43        } else {
  44                r /= 1000;
  45                r_unit = 'k';
  46        }
  47
  48        /* calculate how many ns until we wrap */
  49        wrap = cyc_to_ns((1ULL << clock_bits) - 1, cd->mult, cd->shift);
  50        do_div(wrap, NSEC_PER_MSEC);
  51        w = wrap;
  52
  53        /* calculate the ns resolution of this counter */
  54        res = cyc_to_ns(1ULL, cd->mult, cd->shift);
  55        pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lums\n",
  56                clock_bits, r, r_unit, res, w);
  57
  58        /*
  59         * Start the timer to keep sched_clock() properly updated and
  60         * sets the initial epoch.
  61         */
  62        sched_clock_timer.data = msecs_to_jiffies(w - (w / 10));
  63        update();
  64
  65        /*
  66         * Ensure that sched_clock() starts off at 0ns
  67         */
  68        cd->epoch_ns = 0;
  69}
  70
  71void __init sched_clock_postinit(void)
  72{
  73        sched_clock_poll(sched_clock_timer.data);
  74}
  75