Skip to content

Commit 4914d7b

Browse files
rth7680mattst88
authored andcommitted
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>
1 parent a1659d6 commit 4914d7b

File tree

4 files changed

+165
-7
lines changed

4 files changed

+165
-7
lines changed

arch/alpha/include/asm/pal.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,75 @@ __CALL_PAL_RW1(wtint, unsigned long, unsigned long);
112112
#define tbiap() __tbi(-1, /* no second argument */)
113113
#define tbia() __tbi(-2, /* no second argument */)
114114

115+
/*
116+
* QEMU Cserv routines..
117+
*/
118+
119+
static inline unsigned long
120+
qemu_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+
133+
static inline unsigned long
134+
qemu_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+
147+
static inline void
148+
qemu_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+
159+
static inline void
160+
qemu_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+
171+
static inline unsigned long
172+
qemu_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+
115185
#endif /* !__ASSEMBLY__ */
116186
#endif /* __ALPHA_PAL_H */

arch/alpha/kernel/irq_alpha.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
214214
*/
215215

216216
struct irqaction timer_irqaction = {
217-
.handler = timer_interrupt,
217+
.handler = rtc_timer_interrupt,
218218
.name = "timer",
219219
};
220220

arch/alpha/kernel/proto.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ extern void handle_ipi(struct pt_regs *);
140140
/* extern void reset_for_srm(void); */
141141

142142
/* time.c */
143-
extern irqreturn_t timer_interrupt(int irq, void *dev);
143+
extern irqreturn_t rtc_timer_interrupt(int irq, void *dev);
144144
extern void init_clockevent(void);
145145
extern void common_init_rtc(void);
146146
extern unsigned long est_cycle_freq;

arch/alpha/kernel/time.c

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static inline __u32 rpcc(void)
8787
static DEFINE_PER_CPU(struct clock_event_device, cpu_ce);
8888

8989
irqreturn_t
90-
timer_interrupt(int irq, void *dev)
90+
rtc_timer_interrupt(int irq, void *dev)
9191
{
9292
int cpu = smp_processor_id();
9393
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)
118118
return -EINVAL;
119119
}
120120

121-
void __init
122-
init_clockevent(void)
121+
static void __init
122+
init_rtc_clockevent(void)
123123
{
124124
int cpu = smp_processor_id();
125125
struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);
@@ -136,6 +136,75 @@ init_clockevent(void)
136136
clockevents_config_and_register(ce, CONFIG_HZ, 0, 0);
137137
}
138138

139+
140+
/*
141+
* The QEMU clock as a clocksource primitive.
142+
*/
143+
144+
static cycle_t
145+
qemu_cs_read(struct clocksource *cs)
146+
{
147+
return qemu_get_vmtime();
148+
}
149+
150+
static 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+
164+
static void
165+
qemu_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+
172+
static int
173+
qemu_ce_set_next_event(unsigned long evt, struct clock_event_device *ce)
174+
{
175+
qemu_set_alarm_rel(evt);
176+
return 0;
177+
}
178+
179+
static irqreturn_t
180+
qemu_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+
189+
static void __init
190+
init_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+
139208
void __init
140209
common_init_rtc(void)
141210
{
@@ -329,6 +398,15 @@ time_init(void)
329398
unsigned long cycle_freq, tolerance;
330399
long diff;
331400

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+
332410
/* Calibrate CPU clock -- attempt #1. */
333411
if (!est_cycle_freq)
334412
est_cycle_freq = validate_cc_value(calibrate_cc_with_pit());
@@ -371,7 +449,17 @@ time_init(void)
371449

372450
/* Startup the timer source. */
373451
alpha_mv.init_rtc();
452+
init_rtc_clockevent();
453+
}
374454

375-
/* Start up the clock event device. */
376-
init_clockevent();
455+
/* Initialize the clock_event_device for secondary cpus. */
456+
#ifdef CONFIG_SMP
457+
void __init
458+
init_clockevent(void)
459+
{
460+
if (alpha_using_qemu)
461+
init_qemu_clockevent();
462+
else
463+
init_rtc_clockevent();
377464
}
465+
#endif

0 commit comments

Comments
 (0)