1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/smp.h>
24#include <linux/interrupt.h>
25#include <linux/cpumask.h>
26#include <linux/clocksource.h>
27#include <linux/clockchips.h>
28
29#include <asm/vmi.h>
30#include <asm/vmi_time.h>
31#include <asm/apicdef.h>
32#include <asm/apic.h>
33#include <asm/timer.h>
34#include <asm/i8253.h>
35#include <asm/irq_vectors.h>
36
37#define VMI_ONESHOT (VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
38#define VMI_PERIODIC (VMI_ALARM_IS_PERIODIC | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
39
40static DEFINE_PER_CPU(struct clock_event_device, local_events);
41
42static inline u32 vmi_counter(u32 flags)
43{
44
45
46 return flags & VMI_ALARM_COUNTER_MASK;
47}
48
49
50unsigned long vmi_get_wallclock(void)
51{
52 unsigned long long wallclock;
53 wallclock = vmi_timer_ops.get_wallclock();
54 (void)do_div(wallclock, 1000000000);
55
56 return wallclock;
57}
58
59
60int vmi_set_wallclock(unsigned long now)
61{
62 return 0;
63}
64
65
66unsigned long long vmi_sched_clock(void)
67{
68 return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
69}
70
71
72unsigned long vmi_tsc_khz(void)
73{
74 unsigned long long khz;
75 khz = vmi_timer_ops.get_cycle_frequency();
76 (void)do_div(khz, 1000);
77 return khz;
78}
79
80static inline unsigned int vmi_get_timer_vector(void)
81{
82#ifdef CONFIG_X86_IO_APIC
83 return FIRST_DEVICE_VECTOR;
84#else
85 return FIRST_EXTERNAL_VECTOR;
86#endif
87}
88
89
90#ifdef CONFIG_X86_LOCAL_APIC
91static unsigned int startup_timer_irq(unsigned int irq)
92{
93 unsigned long val = apic_read(APIC_LVTT);
94 apic_write(APIC_LVTT, vmi_get_timer_vector());
95
96 return (val & APIC_SEND_PENDING);
97}
98
99static void mask_timer_irq(unsigned int irq)
100{
101 unsigned long val = apic_read(APIC_LVTT);
102 apic_write(APIC_LVTT, val | APIC_LVT_MASKED);
103}
104
105static void unmask_timer_irq(unsigned int irq)
106{
107 unsigned long val = apic_read(APIC_LVTT);
108 apic_write(APIC_LVTT, val & ~APIC_LVT_MASKED);
109}
110
111static void ack_timer_irq(unsigned int irq)
112{
113 ack_APIC_irq();
114}
115
116static struct irq_chip vmi_chip __read_mostly = {
117 .name = "VMI-LOCAL",
118 .startup = startup_timer_irq,
119 .mask = mask_timer_irq,
120 .unmask = unmask_timer_irq,
121 .ack = ack_timer_irq
122};
123#endif
124
125
126#define VMI_ALARM_WIRED_IRQ0 0x00000000
127#define VMI_ALARM_WIRED_LVTT 0x00010000
128static int vmi_wiring = VMI_ALARM_WIRED_IRQ0;
129
130static inline int vmi_get_alarm_wiring(void)
131{
132 return vmi_wiring;
133}
134
135static void vmi_timer_set_mode(enum clock_event_mode mode,
136 struct clock_event_device *evt)
137{
138 cycle_t now, cycles_per_hz;
139 BUG_ON(!irqs_disabled());
140
141 switch (mode) {
142 case CLOCK_EVT_MODE_ONESHOT:
143 case CLOCK_EVT_MODE_RESUME:
144 break;
145 case CLOCK_EVT_MODE_PERIODIC:
146 cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
147 (void)do_div(cycles_per_hz, HZ);
148 now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_PERIODIC));
149 vmi_timer_ops.set_alarm(VMI_PERIODIC, now, cycles_per_hz);
150 break;
151 case CLOCK_EVT_MODE_UNUSED:
152 case CLOCK_EVT_MODE_SHUTDOWN:
153 switch (evt->mode) {
154 case CLOCK_EVT_MODE_ONESHOT:
155 vmi_timer_ops.cancel_alarm(VMI_ONESHOT);
156 break;
157 case CLOCK_EVT_MODE_PERIODIC:
158 vmi_timer_ops.cancel_alarm(VMI_PERIODIC);
159 break;
160 default:
161 break;
162 }
163 break;
164 default:
165 break;
166 }
167}
168
169static int vmi_timer_next_event(unsigned long delta,
170 struct clock_event_device *evt)
171{
172
173
174
175
176
177 cycle_t now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_ONESHOT));
178
179 BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
180 vmi_timer_ops.set_alarm(VMI_ONESHOT, now + delta, 0);
181 return 0;
182}
183
184static struct clock_event_device vmi_clockevent = {
185 .name = "vmi-timer",
186 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
187 .shift = 22,
188 .set_mode = vmi_timer_set_mode,
189 .set_next_event = vmi_timer_next_event,
190 .rating = 1000,
191 .irq = 0,
192};
193
194static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
195{
196 struct clock_event_device *evt = &__get_cpu_var(local_events);
197 evt->event_handler(evt);
198 return IRQ_HANDLED;
199}
200
201static struct irqaction vmi_clock_action = {
202 .name = "vmi-timer",
203 .handler = vmi_timer_interrupt,
204 .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
205};
206
207static void __devinit vmi_time_init_clockevent(void)
208{
209 cycle_t cycles_per_msec;
210 struct clock_event_device *evt;
211
212 int cpu = smp_processor_id();
213 evt = &__get_cpu_var(local_events);
214
215
216 cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
217 (void)do_div(cycles_per_msec, 1000);
218
219 memcpy(evt, &vmi_clockevent, sizeof(*evt));
220
221
222
223 evt->mult = div_sc(cycles_per_msec, NSEC_PER_MSEC, evt->shift);
224
225 evt->max_delta_ns = clockevent_delta2ns(ULONG_MAX, evt);
226 evt->min_delta_ns = clockevent_delta2ns(1, evt);
227 evt->cpumask = cpumask_of(cpu);
228
229 printk(KERN_WARNING "vmi: registering clock event %s. mult=%lu shift=%u\n",
230 evt->name, evt->mult, evt->shift);
231 clockevents_register_device(evt);
232}
233
234void __init vmi_time_init(void)
235{
236 unsigned int cpu;
237
238 outb_pit(0x3a, PIT_MODE);
239
240 vmi_time_init_clockevent();
241 setup_irq(0, &vmi_clock_action);
242 for_each_possible_cpu(cpu)
243 per_cpu(vector_irq, cpu)[vmi_get_timer_vector()] = 0;
244}
245
246#ifdef CONFIG_X86_LOCAL_APIC
247void __devinit vmi_time_bsp_init(void)
248{
249
250
251
252
253
254
255 clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
256 local_irq_disable();
257#ifdef CONFIG_SMP
258
259
260
261
262
263
264
265
266 set_irq_chip_and_handler_name(0, &vmi_chip, handle_percpu_irq, "lvtt");
267#else
268 set_irq_chip_and_handler_name(0, &vmi_chip, handle_edge_irq, "lvtt");
269#endif
270 vmi_wiring = VMI_ALARM_WIRED_LVTT;
271 apic_write(APIC_LVTT, vmi_get_timer_vector());
272 local_irq_enable();
273 clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
274}
275
276void __devinit vmi_time_ap_init(void)
277{
278 vmi_time_init_clockevent();
279 apic_write(APIC_LVTT, vmi_get_timer_vector());
280}
281#endif
282
283
284static struct clocksource clocksource_vmi;
285
286static cycle_t read_real_cycles(struct clocksource *cs)
287{
288 cycle_t ret = (cycle_t)vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
289 return max(ret, clocksource_vmi.cycle_last);
290}
291
292static struct clocksource clocksource_vmi = {
293 .name = "vmi-timer",
294 .rating = 450,
295 .read = read_real_cycles,
296 .mask = CLOCKSOURCE_MASK(64),
297 .mult = 0,
298 .shift = 22,
299 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
300};
301
302static int __init init_vmi_clocksource(void)
303{
304 cycle_t cycles_per_msec;
305
306 if (!vmi_timer_ops.get_cycle_frequency)
307 return 0;
308
309 cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
310 (void)do_div(cycles_per_msec, 1000);
311
312
313
314 clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec,
315 clocksource_vmi.shift);
316
317 printk(KERN_WARNING "vmi: registering clock source khz=%lld\n", cycles_per_msec);
318 return clocksource_register(&clocksource_vmi);
319
320}
321module_init(init_vmi_clocksource);
322