1 | /* |
2 | * QEMU Sparc SLAVIO timer controller emulation |
3 | * |
4 | * Copyright (c) 2003-2005 Fabrice Bellard |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to deal |
8 | * in the Software without restriction, including without limitation the rights |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | * copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | * THE SOFTWARE. |
23 | */ |
24 | |
25 | #include "qemu/osdep.h" |
26 | #include "qemu/timer.h" |
27 | #include "hw/irq.h" |
28 | #include "hw/ptimer.h" |
29 | #include "hw/qdev-properties.h" |
30 | #include "hw/sysbus.h" |
31 | #include "migration/vmstate.h" |
32 | #include "trace.h" |
33 | #include "qemu/main-loop.h" |
34 | #include "qemu/module.h" |
35 | |
36 | /* |
37 | * Registers of hardware timer in sun4m. |
38 | * |
39 | * This is the timer/counter part of chip STP2001 (Slave I/O), also |
40 | * produced as NCR89C105. See |
41 | * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt |
42 | * |
43 | * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 |
44 | * are zero. Bit 31 is 1 when count has been reached. |
45 | * |
46 | * Per-CPU timers interrupt local CPU, system timer uses normal |
47 | * interrupt routing. |
48 | * |
49 | */ |
50 | |
51 | #define MAX_CPUS 16 |
52 | |
53 | typedef struct CPUTimerState { |
54 | qemu_irq irq; |
55 | ptimer_state *timer; |
56 | uint32_t count, counthigh, reached; |
57 | /* processor only */ |
58 | uint32_t run; |
59 | uint64_t limit; |
60 | } CPUTimerState; |
61 | |
62 | #define TYPE_SLAVIO_TIMER "slavio_timer" |
63 | #define SLAVIO_TIMER(obj) \ |
64 | OBJECT_CHECK(SLAVIO_TIMERState, (obj), TYPE_SLAVIO_TIMER) |
65 | |
66 | typedef struct SLAVIO_TIMERState { |
67 | SysBusDevice parent_obj; |
68 | |
69 | uint32_t num_cpus; |
70 | uint32_t cputimer_mode; |
71 | CPUTimerState cputimer[MAX_CPUS + 1]; |
72 | } SLAVIO_TIMERState; |
73 | |
74 | typedef struct TimerContext { |
75 | MemoryRegion iomem; |
76 | SLAVIO_TIMERState *s; |
77 | unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */ |
78 | } TimerContext; |
79 | |
80 | #define SYS_TIMER_SIZE 0x14 |
81 | #define CPU_TIMER_SIZE 0x10 |
82 | |
83 | #define TIMER_LIMIT 0 |
84 | #define TIMER_COUNTER 1 |
85 | #define TIMER_COUNTER_NORST 2 |
86 | #define TIMER_STATUS 3 |
87 | #define TIMER_MODE 4 |
88 | |
89 | #define TIMER_COUNT_MASK32 0xfffffe00 |
90 | #define TIMER_LIMIT_MASK32 0x7fffffff |
91 | #define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL |
92 | #define TIMER_MAX_COUNT32 0x7ffffe00ULL |
93 | #define TIMER_REACHED 0x80000000 |
94 | #define TIMER_PERIOD 500ULL // 500ns |
95 | #define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1) |
96 | #define PERIODS_TO_LIMIT(l) (((l) + 1) << 9) |
97 | |
98 | static int slavio_timer_is_user(TimerContext *tc) |
99 | { |
100 | SLAVIO_TIMERState *s = tc->s; |
101 | unsigned int timer_index = tc->timer_index; |
102 | |
103 | return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1))); |
104 | } |
105 | |
106 | // Update count, set irq, update expire_time |
107 | // Convert from ptimer countdown units |
108 | static void slavio_timer_get_out(CPUTimerState *t) |
109 | { |
110 | uint64_t count, limit; |
111 | |
112 | if (t->limit == 0) { /* free-run system or processor counter */ |
113 | limit = TIMER_MAX_COUNT32; |
114 | } else { |
115 | limit = t->limit; |
116 | } |
117 | count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer)); |
118 | |
119 | trace_slavio_timer_get_out(t->limit, t->counthigh, t->count); |
120 | t->count = count & TIMER_COUNT_MASK32; |
121 | t->counthigh = count >> 32; |
122 | } |
123 | |
124 | // timer callback |
125 | static void slavio_timer_irq(void *opaque) |
126 | { |
127 | TimerContext *tc = opaque; |
128 | SLAVIO_TIMERState *s = tc->s; |
129 | CPUTimerState *t = &s->cputimer[tc->timer_index]; |
130 | |
131 | slavio_timer_get_out(t); |
132 | trace_slavio_timer_irq(t->counthigh, t->count); |
133 | /* if limit is 0 (free-run), there will be no match */ |
134 | if (t->limit != 0) { |
135 | t->reached = TIMER_REACHED; |
136 | } |
137 | /* there is no interrupt if user timer or free-run */ |
138 | if (!slavio_timer_is_user(tc) && t->limit != 0) { |
139 | qemu_irq_raise(t->irq); |
140 | } |
141 | } |
142 | |
143 | static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr, |
144 | unsigned size) |
145 | { |
146 | TimerContext *tc = opaque; |
147 | SLAVIO_TIMERState *s = tc->s; |
148 | uint32_t saddr, ret; |
149 | unsigned int timer_index = tc->timer_index; |
150 | CPUTimerState *t = &s->cputimer[timer_index]; |
151 | |
152 | saddr = addr >> 2; |
153 | switch (saddr) { |
154 | case TIMER_LIMIT: |
155 | // read limit (system counter mode) or read most signifying |
156 | // part of counter (user mode) |
157 | if (slavio_timer_is_user(tc)) { |
158 | // read user timer MSW |
159 | slavio_timer_get_out(t); |
160 | ret = t->counthigh | t->reached; |
161 | } else { |
162 | // read limit |
163 | // clear irq |
164 | qemu_irq_lower(t->irq); |
165 | t->reached = 0; |
166 | ret = t->limit & TIMER_LIMIT_MASK32; |
167 | } |
168 | break; |
169 | case TIMER_COUNTER: |
170 | // read counter and reached bit (system mode) or read lsbits |
171 | // of counter (user mode) |
172 | slavio_timer_get_out(t); |
173 | if (slavio_timer_is_user(tc)) { // read user timer LSW |
174 | ret = t->count & TIMER_MAX_COUNT64; |
175 | } else { // read limit |
176 | ret = (t->count & TIMER_MAX_COUNT32) | |
177 | t->reached; |
178 | } |
179 | break; |
180 | case TIMER_STATUS: |
181 | // only available in processor counter/timer |
182 | // read start/stop status |
183 | if (timer_index > 0) { |
184 | ret = t->run; |
185 | } else { |
186 | ret = 0; |
187 | } |
188 | break; |
189 | case TIMER_MODE: |
190 | // only available in system counter |
191 | // read user/system mode |
192 | ret = s->cputimer_mode; |
193 | break; |
194 | default: |
195 | trace_slavio_timer_mem_readl_invalid(addr); |
196 | ret = 0; |
197 | break; |
198 | } |
199 | trace_slavio_timer_mem_readl(addr, ret); |
200 | return ret; |
201 | } |
202 | |
203 | static void slavio_timer_mem_writel(void *opaque, hwaddr addr, |
204 | uint64_t val, unsigned size) |
205 | { |
206 | TimerContext *tc = opaque; |
207 | SLAVIO_TIMERState *s = tc->s; |
208 | uint32_t saddr; |
209 | unsigned int timer_index = tc->timer_index; |
210 | CPUTimerState *t = &s->cputimer[timer_index]; |
211 | |
212 | trace_slavio_timer_mem_writel(addr, val); |
213 | saddr = addr >> 2; |
214 | switch (saddr) { |
215 | case TIMER_LIMIT: |
216 | if (slavio_timer_is_user(tc)) { |
217 | uint64_t count; |
218 | |
219 | // set user counter MSW, reset counter |
220 | t->limit = TIMER_MAX_COUNT64; |
221 | t->counthigh = val & (TIMER_MAX_COUNT64 >> 32); |
222 | t->reached = 0; |
223 | count = ((uint64_t)t->counthigh << 32) | t->count; |
224 | trace_slavio_timer_mem_writel_limit(timer_index, count); |
225 | ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); |
226 | } else { |
227 | // set limit, reset counter |
228 | qemu_irq_lower(t->irq); |
229 | t->limit = val & TIMER_MAX_COUNT32; |
230 | if (t->timer) { |
231 | if (t->limit == 0) { /* free-run */ |
232 | ptimer_set_limit(t->timer, |
233 | LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); |
234 | } else { |
235 | ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); |
236 | } |
237 | } |
238 | } |
239 | break; |
240 | case TIMER_COUNTER: |
241 | if (slavio_timer_is_user(tc)) { |
242 | uint64_t count; |
243 | |
244 | // set user counter LSW, reset counter |
245 | t->limit = TIMER_MAX_COUNT64; |
246 | t->count = val & TIMER_MAX_COUNT64; |
247 | t->reached = 0; |
248 | count = ((uint64_t)t->counthigh) << 32 | t->count; |
249 | trace_slavio_timer_mem_writel_limit(timer_index, count); |
250 | ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); |
251 | } else { |
252 | trace_slavio_timer_mem_writel_counter_invalid(); |
253 | } |
254 | break; |
255 | case TIMER_COUNTER_NORST: |
256 | // set limit without resetting counter |
257 | t->limit = val & TIMER_MAX_COUNT32; |
258 | if (t->limit == 0) { /* free-run */ |
259 | ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); |
260 | } else { |
261 | ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0); |
262 | } |
263 | break; |
264 | case TIMER_STATUS: |
265 | if (slavio_timer_is_user(tc)) { |
266 | // start/stop user counter |
267 | if (val & 1) { |
268 | trace_slavio_timer_mem_writel_status_start(timer_index); |
269 | ptimer_run(t->timer, 0); |
270 | } else { |
271 | trace_slavio_timer_mem_writel_status_stop(timer_index); |
272 | ptimer_stop(t->timer); |
273 | } |
274 | } |
275 | t->run = val & 1; |
276 | break; |
277 | case TIMER_MODE: |
278 | if (timer_index == 0) { |
279 | unsigned int i; |
280 | |
281 | for (i = 0; i < s->num_cpus; i++) { |
282 | unsigned int processor = 1 << i; |
283 | CPUTimerState *curr_timer = &s->cputimer[i + 1]; |
284 | |
285 | // check for a change in timer mode for this processor |
286 | if ((val & processor) != (s->cputimer_mode & processor)) { |
287 | if (val & processor) { // counter -> user timer |
288 | qemu_irq_lower(curr_timer->irq); |
289 | // counters are always running |
290 | if (!curr_timer->run) { |
291 | ptimer_stop(curr_timer->timer); |
292 | } |
293 | // user timer limit is always the same |
294 | curr_timer->limit = TIMER_MAX_COUNT64; |
295 | ptimer_set_limit(curr_timer->timer, |
296 | LIMIT_TO_PERIODS(curr_timer->limit), |
297 | 1); |
298 | // set this processors user timer bit in config |
299 | // register |
300 | s->cputimer_mode |= processor; |
301 | trace_slavio_timer_mem_writel_mode_user(timer_index); |
302 | } else { // user timer -> counter |
303 | // start the counter |
304 | ptimer_run(curr_timer->timer, 0); |
305 | // clear this processors user timer bit in config |
306 | // register |
307 | s->cputimer_mode &= ~processor; |
308 | trace_slavio_timer_mem_writel_mode_counter(timer_index); |
309 | } |
310 | } |
311 | } |
312 | } else { |
313 | trace_slavio_timer_mem_writel_mode_invalid(); |
314 | } |
315 | break; |
316 | default: |
317 | trace_slavio_timer_mem_writel_invalid(addr); |
318 | break; |
319 | } |
320 | } |
321 | |
322 | static const MemoryRegionOps slavio_timer_mem_ops = { |
323 | .read = slavio_timer_mem_readl, |
324 | .write = slavio_timer_mem_writel, |
325 | .endianness = DEVICE_NATIVE_ENDIAN, |
326 | .valid = { |
327 | .min_access_size = 4, |
328 | .max_access_size = 4, |
329 | }, |
330 | }; |
331 | |
332 | static const VMStateDescription vmstate_timer = { |
333 | .name ="timer" , |
334 | .version_id = 3, |
335 | .minimum_version_id = 3, |
336 | .fields = (VMStateField[]) { |
337 | VMSTATE_UINT64(limit, CPUTimerState), |
338 | VMSTATE_UINT32(count, CPUTimerState), |
339 | VMSTATE_UINT32(counthigh, CPUTimerState), |
340 | VMSTATE_UINT32(reached, CPUTimerState), |
341 | VMSTATE_UINT32(run , CPUTimerState), |
342 | VMSTATE_PTIMER(timer, CPUTimerState), |
343 | VMSTATE_END_OF_LIST() |
344 | } |
345 | }; |
346 | |
347 | static const VMStateDescription vmstate_slavio_timer = { |
348 | .name ="slavio_timer" , |
349 | .version_id = 3, |
350 | .minimum_version_id = 3, |
351 | .fields = (VMStateField[]) { |
352 | VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3, |
353 | vmstate_timer, CPUTimerState), |
354 | VMSTATE_END_OF_LIST() |
355 | } |
356 | }; |
357 | |
358 | static void slavio_timer_reset(DeviceState *d) |
359 | { |
360 | SLAVIO_TIMERState *s = SLAVIO_TIMER(d); |
361 | unsigned int i; |
362 | CPUTimerState *curr_timer; |
363 | |
364 | for (i = 0; i <= MAX_CPUS; i++) { |
365 | curr_timer = &s->cputimer[i]; |
366 | curr_timer->limit = 0; |
367 | curr_timer->count = 0; |
368 | curr_timer->reached = 0; |
369 | if (i <= s->num_cpus) { |
370 | ptimer_set_limit(curr_timer->timer, |
371 | LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); |
372 | ptimer_run(curr_timer->timer, 0); |
373 | curr_timer->run = 1; |
374 | } |
375 | } |
376 | s->cputimer_mode = 0; |
377 | } |
378 | |
379 | static void slavio_timer_init(Object *obj) |
380 | { |
381 | SLAVIO_TIMERState *s = SLAVIO_TIMER(obj); |
382 | SysBusDevice *dev = SYS_BUS_DEVICE(obj); |
383 | QEMUBH *bh; |
384 | unsigned int i; |
385 | TimerContext *tc; |
386 | |
387 | for (i = 0; i <= MAX_CPUS; i++) { |
388 | uint64_t size; |
389 | char timer_name[20]; |
390 | |
391 | tc = g_malloc0(sizeof(TimerContext)); |
392 | tc->s = s; |
393 | tc->timer_index = i; |
394 | |
395 | bh = qemu_bh_new(slavio_timer_irq, tc); |
396 | s->cputimer[i].timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); |
397 | ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); |
398 | |
399 | size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE; |
400 | snprintf(timer_name, sizeof(timer_name), "timer-%i" , i); |
401 | memory_region_init_io(&tc->iomem, obj, &slavio_timer_mem_ops, tc, |
402 | timer_name, size); |
403 | sysbus_init_mmio(dev, &tc->iomem); |
404 | |
405 | sysbus_init_irq(dev, &s->cputimer[i].irq); |
406 | } |
407 | } |
408 | |
409 | static Property slavio_timer_properties[] = { |
410 | DEFINE_PROP_UINT32("num_cpus" , SLAVIO_TIMERState, num_cpus, 0), |
411 | DEFINE_PROP_END_OF_LIST(), |
412 | }; |
413 | |
414 | static void slavio_timer_class_init(ObjectClass *klass, void *data) |
415 | { |
416 | DeviceClass *dc = DEVICE_CLASS(klass); |
417 | |
418 | dc->reset = slavio_timer_reset; |
419 | dc->vmsd = &vmstate_slavio_timer; |
420 | dc->props = slavio_timer_properties; |
421 | } |
422 | |
423 | static const TypeInfo slavio_timer_info = { |
424 | .name = TYPE_SLAVIO_TIMER, |
425 | .parent = TYPE_SYS_BUS_DEVICE, |
426 | .instance_size = sizeof(SLAVIO_TIMERState), |
427 | .instance_init = slavio_timer_init, |
428 | .class_init = slavio_timer_class_init, |
429 | }; |
430 | |
431 | static void slavio_timer_register_types(void) |
432 | { |
433 | type_register_static(&slavio_timer_info); |
434 | } |
435 | |
436 | type_init(slavio_timer_register_types) |
437 | |