~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/tile/kernel/time.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2010 Tilera Corporation. All Rights Reserved.
 
3
 *
 
4
 *   This program is free software; you can redistribute it and/or
 
5
 *   modify it under the terms of the GNU General Public License
 
6
 *   as published by the Free Software Foundation, version 2.
 
7
 *
 
8
 *   This program is distributed in the hope that it will be useful, but
 
9
 *   WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 
11
 *   NON INFRINGEMENT.  See the GNU General Public License for
 
12
 *   more details.
 
13
 *
 
14
 * Support the cycle counter clocksource and tile timer clock event device.
 
15
 */
 
16
 
 
17
#include <linux/time.h>
 
18
#include <linux/timex.h>
 
19
#include <linux/clocksource.h>
 
20
#include <linux/clockchips.h>
 
21
#include <linux/hardirq.h>
 
22
#include <linux/sched.h>
 
23
#include <linux/smp.h>
 
24
#include <linux/delay.h>
 
25
#include <linux/module.h>
 
26
#include <asm/irq_regs.h>
 
27
#include <asm/traps.h>
 
28
#include <hv/hypervisor.h>
 
29
#include <arch/interrupts.h>
 
30
#include <arch/spr_def.h>
 
31
 
 
32
 
 
33
/*
 
34
 * Define the cycle counter clock source.
 
35
 */
 
36
 
 
37
/* How many cycles per second we are running at. */
 
38
static cycles_t cycles_per_sec __write_once;
 
39
 
 
40
cycles_t get_clock_rate(void)
 
41
{
 
42
        return cycles_per_sec;
 
43
}
 
44
 
 
45
#if CHIP_HAS_SPLIT_CYCLE()
 
46
cycles_t get_cycles(void)
 
47
{
 
48
        unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH);
 
49
        unsigned int low = __insn_mfspr(SPR_CYCLE_LOW);
 
50
        unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH);
 
51
 
 
52
        while (unlikely(high != high2)) {
 
53
                low = __insn_mfspr(SPR_CYCLE_LOW);
 
54
                high = high2;
 
55
                high2 = __insn_mfspr(SPR_CYCLE_HIGH);
 
56
        }
 
57
 
 
58
        return (((cycles_t)high) << 32) | low;
 
59
}
 
60
EXPORT_SYMBOL(get_cycles);
 
61
#endif
 
62
 
 
63
/*
 
64
 * We use a relatively small shift value so that sched_clock()
 
65
 * won't wrap around very often.
 
66
 */
 
67
#define SCHED_CLOCK_SHIFT 10
 
68
 
 
69
static unsigned long sched_clock_mult __write_once;
 
70
 
 
71
static cycles_t clocksource_get_cycles(struct clocksource *cs)
 
72
{
 
73
        return get_cycles();
 
74
}
 
75
 
 
76
static struct clocksource cycle_counter_cs = {
 
77
        .name = "cycle counter",
 
78
        .rating = 300,
 
79
        .read = clocksource_get_cycles,
 
80
        .mask = CLOCKSOURCE_MASK(64),
 
81
        .flags = CLOCK_SOURCE_IS_CONTINUOUS,
 
82
};
 
83
 
 
84
/*
 
85
 * Called very early from setup_arch() to set cycles_per_sec.
 
86
 * We initialize it early so we can use it to set up loops_per_jiffy.
 
87
 */
 
88
void __init setup_clock(void)
 
89
{
 
90
        cycles_per_sec = hv_sysconf(HV_SYSCONF_CPU_SPEED);
 
91
        sched_clock_mult =
 
92
                clocksource_hz2mult(cycles_per_sec, SCHED_CLOCK_SHIFT);
 
93
}
 
94
 
 
95
void __init calibrate_delay(void)
 
96
{
 
97
        loops_per_jiffy = get_clock_rate() / HZ;
 
98
        pr_info("Clock rate yields %lu.%02lu BogoMIPS (lpj=%lu)\n",
 
99
                loops_per_jiffy/(500000/HZ),
 
100
                (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy);
 
101
}
 
102
 
 
103
/* Called fairly late in init/main.c, but before we go smp. */
 
104
void __init time_init(void)
 
105
{
 
106
        /* Initialize and register the clock source. */
 
107
        clocksource_register_hz(&cycle_counter_cs, cycles_per_sec);
 
108
 
 
109
        /* Start up the tile-timer interrupt source on the boot cpu. */
 
110
        setup_tile_timer();
 
111
}
 
112
 
 
113
 
 
114
/*
 
115
 * Define the tile timer clock event device.  The timer is driven by
 
116
 * the TILE_TIMER_CONTROL register, which consists of a 31-bit down
 
117
 * counter, plus bit 31, which signifies that the counter has wrapped
 
118
 * from zero to (2**31) - 1.  The INT_TILE_TIMER interrupt will be
 
119
 * raised as long as bit 31 is set.
 
120
 *
 
121
 * The TILE_MINSEC value represents the largest range of real-time
 
122
 * we can possibly cover with the timer, based on MAX_TICK combined
 
123
 * with the slowest reasonable clock rate we might run at.
 
124
 */
 
125
 
 
126
#define MAX_TICK 0x7fffffff   /* we have 31 bits of countdown timer */
 
127
#define TILE_MINSEC 5         /* timer covers no more than 5 seconds */
 
128
 
 
129
static int tile_timer_set_next_event(unsigned long ticks,
 
130
                                     struct clock_event_device *evt)
 
131
{
 
132
        BUG_ON(ticks > MAX_TICK);
 
133
        __insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks);
 
134
        arch_local_irq_unmask_now(INT_TILE_TIMER);
 
135
        return 0;
 
136
}
 
137
 
 
138
/*
 
139
 * Whenever anyone tries to change modes, we just mask interrupts
 
140
 * and wait for the next event to get set.
 
141
 */
 
142
static void tile_timer_set_mode(enum clock_event_mode mode,
 
143
                                struct clock_event_device *evt)
 
144
{
 
145
        arch_local_irq_mask_now(INT_TILE_TIMER);
 
146
}
 
147
 
 
148
/*
 
149
 * Set min_delta_ns to 1 microsecond, since it takes about
 
150
 * that long to fire the interrupt.
 
151
 */
 
152
static DEFINE_PER_CPU(struct clock_event_device, tile_timer) = {
 
153
        .name = "tile timer",
 
154
        .features = CLOCK_EVT_FEAT_ONESHOT,
 
155
        .min_delta_ns = 1000,
 
156
        .rating = 100,
 
157
        .irq = -1,
 
158
        .set_next_event = tile_timer_set_next_event,
 
159
        .set_mode = tile_timer_set_mode,
 
160
};
 
161
 
 
162
void __cpuinit setup_tile_timer(void)
 
163
{
 
164
        struct clock_event_device *evt = &__get_cpu_var(tile_timer);
 
165
 
 
166
        /* Fill in fields that are speed-specific. */
 
167
        clockevents_calc_mult_shift(evt, cycles_per_sec, TILE_MINSEC);
 
168
        evt->max_delta_ns = clockevent_delta2ns(MAX_TICK, evt);
 
169
 
 
170
        /* Mark as being for this cpu only. */
 
171
        evt->cpumask = cpumask_of(smp_processor_id());
 
172
 
 
173
        /* Start out with timer not firing. */
 
174
        arch_local_irq_mask_now(INT_TILE_TIMER);
 
175
 
 
176
        /* Register tile timer. */
 
177
        clockevents_register_device(evt);
 
178
}
 
179
 
 
180
/* Called from the interrupt vector. */
 
181
void do_timer_interrupt(struct pt_regs *regs, int fault_num)
 
182
{
 
183
        struct pt_regs *old_regs = set_irq_regs(regs);
 
184
        struct clock_event_device *evt = &__get_cpu_var(tile_timer);
 
185
 
 
186
        /*
 
187
         * Mask the timer interrupt here, since we are a oneshot timer
 
188
         * and there are now by definition no events pending.
 
189
         */
 
190
        arch_local_irq_mask(INT_TILE_TIMER);
 
191
 
 
192
        /* Track time spent here in an interrupt context */
 
193
        irq_enter();
 
194
 
 
195
        /* Track interrupt count. */
 
196
        __get_cpu_var(irq_stat).irq_timer_count++;
 
197
 
 
198
        /* Call the generic timer handler */
 
199
        evt->event_handler(evt);
 
200
 
 
201
        /*
 
202
         * Track time spent against the current process again and
 
203
         * process any softirqs if they are waiting.
 
204
         */
 
205
        irq_exit();
 
206
 
 
207
        set_irq_regs(old_regs);
 
208
}
 
209
 
 
210
/*
 
211
 * Scheduler clock - returns current time in nanosec units.
 
212
 * Note that with LOCKDEP, this is called during lockdep_init(), and
 
213
 * we will claim that sched_clock() is zero for a little while, until
 
214
 * we run setup_clock(), above.
 
215
 */
 
216
unsigned long long sched_clock(void)
 
217
{
 
218
        return clocksource_cyc2ns(get_cycles(),
 
219
                                  sched_clock_mult, SCHED_CLOCK_SHIFT);
 
220
}
 
221
 
 
222
int setup_profiling_timer(unsigned int multiplier)
 
223
{
 
224
        return -EINVAL;
 
225
}
 
226
 
 
227
/*
 
228
 * Use the tile timer to convert nsecs to core clock cycles, relying
 
229
 * on it having the same frequency as SPR_CYCLE.
 
230
 */
 
231
cycles_t ns2cycles(unsigned long nsecs)
 
232
{
 
233
        struct clock_event_device *dev = &__get_cpu_var(tile_timer);
 
234
        return ((u64)nsecs * dev->mult) >> dev->shift;
 
235
}