aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2013-07-14 17:50:21 -0400
committerMatt Turner <mattst88@gmail.com>2013-11-16 19:33:21 -0500
commit4914d7b458e35a7db2f9c7dc6eb014620254bbbf (patch)
tree07bc9c2eedb174f0710dddca3950dcb12789236c
parenta1659d6d128a7e0c2985bce7c957b66af1f71181 (diff)
alpha: Use qemu+cserve provided high-res clock and alarm.
QEMU provides a high-resolution timer and alarm; use this for a clock source and clock event source when available. Signed-off-by: Richard Henderson <rth@twiddle.net>
-rw-r--r--arch/alpha/include/asm/pal.h70
-rw-r--r--arch/alpha/kernel/irq_alpha.c2
-rw-r--r--arch/alpha/kernel/proto.h2
-rw-r--r--arch/alpha/kernel/time.c98
4 files changed, 165 insertions, 7 deletions
diff --git a/arch/alpha/include/asm/pal.h b/arch/alpha/include/asm/pal.h
index e78ec9bcc768..5422a47646fc 100644
--- a/arch/alpha/include/asm/pal.h
+++ b/arch/alpha/include/asm/pal.h
@@ -112,5 +112,75 @@ __CALL_PAL_RW1(wtint, unsigned long, unsigned long);
112#define tbiap() __tbi(-1, /* no second argument */) 112#define tbiap() __tbi(-1, /* no second argument */)
113#define tbia() __tbi(-2, /* no second argument */) 113#define tbia() __tbi(-2, /* no second argument */)
114 114
115/*
116 * QEMU Cserv routines..
117 */
118
119static inline unsigned long
120qemu_get_walltime(void)
121{
122 register unsigned long v0 __asm__("$0");
123 register unsigned long a0 __asm__("$16") = 3;
124
125 asm("call_pal %2 # cserve get_time"
126 : "=r"(v0), "+r"(a0)
127 : "i"(PAL_cserve)
128 : "$17", "$18", "$19", "$20", "$21");
129
130 return v0;
131}
132
133static inline unsigned long
134qemu_get_alarm(void)
135{
136 register unsigned long v0 __asm__("$0");
137 register unsigned long a0 __asm__("$16") = 4;
138
139 asm("call_pal %2 # cserve get_alarm"
140 : "=r"(v0), "+r"(a0)
141 : "i"(PAL_cserve)
142 : "$17", "$18", "$19", "$20", "$21");
143
144 return v0;
145}
146
147static inline void
148qemu_set_alarm_rel(unsigned long expire)
149{
150 register unsigned long a0 __asm__("$16") = 5;
151 register unsigned long a1 __asm__("$17") = expire;
152
153 asm volatile("call_pal %2 # cserve set_alarm_rel"
154 : "+r"(a0), "+r"(a1)
155 : "i"(PAL_cserve)
156 : "$0", "$18", "$19", "$20", "$21");
157}
158
159static inline void
160qemu_set_alarm_abs(unsigned long expire)
161{
162 register unsigned long a0 __asm__("$16") = 6;
163 register unsigned long a1 __asm__("$17") = expire;
164
165 asm volatile("call_pal %2 # cserve set_alarm_abs"
166 : "+r"(a0), "+r"(a1)
167 : "i"(PAL_cserve)
168 : "$0", "$18", "$19", "$20", "$21");
169}
170
171static inline unsigned long
172qemu_get_vmtime(void)
173{
174 register unsigned long v0 __asm__("$0");
175 register unsigned long a0 __asm__("$16") = 7;
176
177 asm("call_pal %2 # cserve get_time"
178 : "=r"(v0), "+r"(a0)
179 : "i"(PAL_cserve)
180 : "$17", "$18", "$19", "$20", "$21");
181
182 return v0;
183}
184
115#endif /* !__ASSEMBLY__ */ 185#endif /* !__ASSEMBLY__ */
116#endif /* __ALPHA_PAL_H */ 186#endif /* __ALPHA_PAL_H */
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index 6990ddc0fbaf..1c8625cb0e25 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -214,7 +214,7 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
214 */ 214 */
215 215
216struct irqaction timer_irqaction = { 216struct irqaction timer_irqaction = {
217 .handler = timer_interrupt, 217 .handler = rtc_timer_interrupt,
218 .name = "timer", 218 .name = "timer",
219}; 219};
220 220
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index bc806893afe0..da2d6ec9c370 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -140,7 +140,7 @@ extern void handle_ipi(struct pt_regs *);
140/* extern void reset_for_srm(void); */ 140/* extern void reset_for_srm(void); */
141 141
142/* time.c */ 142/* time.c */
143extern irqreturn_t timer_interrupt(int irq, void *dev); 143extern irqreturn_t rtc_timer_interrupt(int irq, void *dev);
144extern void init_clockevent(void); 144extern void init_clockevent(void);
145extern void common_init_rtc(void); 145extern void common_init_rtc(void);
146extern unsigned long est_cycle_freq; 146extern unsigned long est_cycle_freq;
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 08ff3f502a76..ee39cee8064c 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -87,7 +87,7 @@ static inline __u32 rpcc(void)
87static DEFINE_PER_CPU(struct clock_event_device, cpu_ce); 87static DEFINE_PER_CPU(struct clock_event_device, cpu_ce);
88 88
89irqreturn_t 89irqreturn_t
90timer_interrupt(int irq, void *dev) 90rtc_timer_interrupt(int irq, void *dev)
91{ 91{
92 int cpu = smp_processor_id(); 92 int cpu = smp_processor_id();
93 struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); 93 struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);
@@ -118,8 +118,8 @@ rtc_ce_set_next_event(unsigned long evt, struct clock_event_device *ce)
118 return -EINVAL; 118 return -EINVAL;
119} 119}
120 120
121void __init 121static void __init
122init_clockevent(void) 122init_rtc_clockevent(void)
123{ 123{
124 int cpu = smp_processor_id(); 124 int cpu = smp_processor_id();
125 struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); 125 struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);
@@ -136,6 +136,75 @@ init_clockevent(void)
136 clockevents_config_and_register(ce, CONFIG_HZ, 0, 0); 136 clockevents_config_and_register(ce, CONFIG_HZ, 0, 0);
137} 137}
138 138
139
140/*
141 * The QEMU clock as a clocksource primitive.
142 */
143
144static cycle_t
145qemu_cs_read(struct clocksource *cs)
146{
147 return qemu_get_vmtime();
148}
149
150static struct clocksource qemu_cs = {
151 .name = "qemu",
152 .rating = 400,
153 .read = qemu_cs_read,
154 .mask = CLOCKSOURCE_MASK(64),
155 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
156 .max_idle_ns = LONG_MAX
157};
158
159
160/*
161 * The QEMU alarm as a clock_event_device primitive.
162 */
163
164static void
165qemu_ce_set_mode(enum clock_event_mode mode, struct clock_event_device *ce)
166{
167 /* The mode member of CE is updated for us in generic code.
168 Just make sure that the event is disabled. */
169 qemu_set_alarm_abs(0);
170}
171
172static int
173qemu_ce_set_next_event(unsigned long evt, struct clock_event_device *ce)
174{
175 qemu_set_alarm_rel(evt);
176 return 0;
177}
178
179static irqreturn_t
180qemu_timer_interrupt(int irq, void *dev)
181{
182 int cpu = smp_processor_id();
183 struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);
184
185 ce->event_handler(ce);
186 return IRQ_HANDLED;
187}
188
189static void __init
190init_qemu_clockevent(void)
191{
192 int cpu = smp_processor_id();
193 struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);
194
195 *ce = (struct clock_event_device){
196 .name = "qemu",
197 .features = CLOCK_EVT_FEAT_ONESHOT,
198 .rating = 400,
199 .cpumask = cpumask_of(cpu),
200 .set_mode = qemu_ce_set_mode,
201 .set_next_event = qemu_ce_set_next_event,
202 };
203
204 clockevents_config_and_register(ce, NSEC_PER_SEC, 1000, LONG_MAX);
205}
206
207
139void __init 208void __init
140common_init_rtc(void) 209common_init_rtc(void)
141{ 210{
@@ -329,6 +398,15 @@ time_init(void)
329 unsigned long cycle_freq, tolerance; 398 unsigned long cycle_freq, tolerance;
330 long diff; 399 long diff;
331 400
401 if (alpha_using_qemu) {
402 clocksource_register_hz(&qemu_cs, NSEC_PER_SEC);
403 init_qemu_clockevent();
404
405 timer_irqaction.handler = qemu_timer_interrupt;
406 init_rtc_irq();
407 return;
408 }
409
332 /* Calibrate CPU clock -- attempt #1. */ 410 /* Calibrate CPU clock -- attempt #1. */
333 if (!est_cycle_freq) 411 if (!est_cycle_freq)
334 est_cycle_freq = validate_cc_value(calibrate_cc_with_pit()); 412 est_cycle_freq = validate_cc_value(calibrate_cc_with_pit());
@@ -371,7 +449,17 @@ time_init(void)
371 449
372 /* Startup the timer source. */ 450 /* Startup the timer source. */
373 alpha_mv.init_rtc(); 451 alpha_mv.init_rtc();
452 init_rtc_clockevent();
453}
374 454
375 /* Start up the clock event device. */ 455/* Initialize the clock_event_device for secondary cpus. */
376 init_clockevent(); 456#ifdef CONFIG_SMP
457void __init
458init_clockevent(void)
459{
460 if (alpha_using_qemu)
461 init_qemu_clockevent();
462 else
463 init_rtc_clockevent();
377} 464}
465#endif