diff options
author | Paul Mackerras <paulus@samba.org> | 2006-03-27 05:48:57 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-03-27 05:48:57 -0500 |
commit | 9618edab82fda8dbce5ea3abcdac9ded07abb2d4 (patch) | |
tree | 8edacdcf4d0ecdd8a7b5b0f88f3cf68c393afbc5 | |
parent | d0cc0dfa2dcf18854144b16a74502bd25c4eaedf (diff) |
powerpc: Fix event-scan code for 32-bit CHRP
On CHRP machines we are supposed to call into firmware (RTAS)
periodically, to give it a chance to check for errors and other
events. Under ppc we had some special code in timer_interrupt
to do this, but that didn't get transferred over to arch/powerpc.
Instead, we use an array of timer_list structs, one per CPU,
and use add_timer_on to make sure each one gets called on the
appropriate CPU.
With this we can remove the heartbeat_* elements of the ppc_md
struct.
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/chrp/chrp.h | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/chrp/setup.c | 64 | ||||
-rw-r--r-- | include/asm-powerpc/machdep.h | 4 |
3 files changed, 46 insertions, 24 deletions
diff --git a/arch/powerpc/platforms/chrp/chrp.h b/arch/powerpc/platforms/chrp/chrp.h index 814f54742e0f..63f0aee4c158 100644 --- a/arch/powerpc/platforms/chrp/chrp.h +++ b/arch/powerpc/platforms/chrp/chrp.h | |||
@@ -8,4 +8,4 @@ extern int chrp_set_rtc_time(struct rtc_time *); | |||
8 | extern long chrp_time_init(void); | 8 | extern long chrp_time_init(void); |
9 | 9 | ||
10 | extern void chrp_find_bridges(void); | 10 | extern void chrp_find_bridges(void); |
11 | extern void chrp_event_scan(void); | 11 | extern void chrp_event_scan(unsigned long); |
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 8bf4307e323d..9c718bb2305e 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/root_dev.h> | 35 | #include <linux/root_dev.h> |
36 | #include <linux/initrd.h> | 36 | #include <linux/initrd.h> |
37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
38 | #include <linux/timer.h> | ||
38 | 39 | ||
39 | #include <asm/io.h> | 40 | #include <asm/io.h> |
40 | #include <asm/pgtable.h> | 41 | #include <asm/pgtable.h> |
@@ -61,6 +62,10 @@ EXPORT_SYMBOL(_chrp_type); | |||
61 | 62 | ||
62 | struct mpic *chrp_mpic; | 63 | struct mpic *chrp_mpic; |
63 | 64 | ||
65 | /* Used for doing CHRP event-scans */ | ||
66 | DEFINE_PER_CPU(struct timer_list, heartbeat_timer); | ||
67 | unsigned long event_scan_interval; | ||
68 | |||
64 | /* | 69 | /* |
65 | * XXX this should be in xmon.h, but putting it there means xmon.h | 70 | * XXX this should be in xmon.h, but putting it there means xmon.h |
66 | * has to include <linux/interrupt.h> (to get irqreturn_t), which | 71 | * has to include <linux/interrupt.h> (to get irqreturn_t), which |
@@ -229,8 +234,6 @@ void __init chrp_setup_arch(void) | |||
229 | { | 234 | { |
230 | struct device_node *root = find_path_device ("/"); | 235 | struct device_node *root = find_path_device ("/"); |
231 | char *machine = NULL; | 236 | char *machine = NULL; |
232 | struct device_node *device; | ||
233 | unsigned int *p = NULL; | ||
234 | 237 | ||
235 | /* init to some ~sane value until calibrate_delay() runs */ | 238 | /* init to some ~sane value until calibrate_delay() runs */ |
236 | loops_per_jiffy = 50000000/HZ; | 239 | loops_per_jiffy = 50000000/HZ; |
@@ -287,21 +290,6 @@ void __init chrp_setup_arch(void) | |||
287 | */ | 290 | */ |
288 | sio_init(); | 291 | sio_init(); |
289 | 292 | ||
290 | /* Get the event scan rate for the rtas so we know how | ||
291 | * often it expects a heartbeat. -- Cort | ||
292 | */ | ||
293 | device = find_devices("rtas"); | ||
294 | if (device) | ||
295 | p = (unsigned int *) get_property | ||
296 | (device, "rtas-event-scan-rate", NULL); | ||
297 | if (p && *p) { | ||
298 | ppc_md.heartbeat = chrp_event_scan; | ||
299 | ppc_md.heartbeat_reset = HZ / (*p * 30) - 1; | ||
300 | ppc_md.heartbeat_count = 1; | ||
301 | printk("RTAS Event Scan Rate: %u (%lu jiffies)\n", | ||
302 | *p, ppc_md.heartbeat_reset); | ||
303 | } | ||
304 | |||
305 | pci_create_OF_bus_map(); | 293 | pci_create_OF_bus_map(); |
306 | 294 | ||
307 | /* | 295 | /* |
@@ -312,7 +300,7 @@ void __init chrp_setup_arch(void) | |||
312 | } | 300 | } |
313 | 301 | ||
314 | void | 302 | void |
315 | chrp_event_scan(void) | 303 | chrp_event_scan(unsigned long unused) |
316 | { | 304 | { |
317 | unsigned char log[1024]; | 305 | unsigned char log[1024]; |
318 | int ret = 0; | 306 | int ret = 0; |
@@ -320,7 +308,8 @@ chrp_event_scan(void) | |||
320 | /* XXX: we should loop until the hardware says no more error logs -- Cort */ | 308 | /* XXX: we should loop until the hardware says no more error logs -- Cort */ |
321 | rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0, | 309 | rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0, |
322 | __pa(log), 1024); | 310 | __pa(log), 1024); |
323 | ppc_md.heartbeat_count = ppc_md.heartbeat_reset; | 311 | mod_timer(&__get_cpu_var(heartbeat_timer), |
312 | jiffies + event_scan_interval); | ||
324 | } | 313 | } |
325 | 314 | ||
326 | /* | 315 | /* |
@@ -465,6 +454,9 @@ void __init chrp_init_IRQ(void) | |||
465 | void __init | 454 | void __init |
466 | chrp_init2(void) | 455 | chrp_init2(void) |
467 | { | 456 | { |
457 | struct device_node *device; | ||
458 | unsigned int *p = NULL; | ||
459 | |||
468 | #ifdef CONFIG_NVRAM | 460 | #ifdef CONFIG_NVRAM |
469 | chrp_nvram_init(); | 461 | chrp_nvram_init(); |
470 | #endif | 462 | #endif |
@@ -476,6 +468,40 @@ chrp_init2(void) | |||
476 | request_region(0x80,0x10,"dma page reg"); | 468 | request_region(0x80,0x10,"dma page reg"); |
477 | request_region(0xc0,0x20,"dma2"); | 469 | request_region(0xc0,0x20,"dma2"); |
478 | 470 | ||
471 | /* Get the event scan rate for the rtas so we know how | ||
472 | * often it expects a heartbeat. -- Cort | ||
473 | */ | ||
474 | device = find_devices("rtas"); | ||
475 | if (device) | ||
476 | p = (unsigned int *) get_property | ||
477 | (device, "rtas-event-scan-rate", NULL); | ||
478 | if (p && *p) { | ||
479 | /* | ||
480 | * Arrange to call chrp_event_scan at least *p times | ||
481 | * per minute. We use 59 rather than 60 here so that | ||
482 | * the rate will be slightly higher than the minimum. | ||
483 | * This all assumes we don't do hotplug CPU on any | ||
484 | * machine that needs the event scans done. | ||
485 | */ | ||
486 | unsigned long interval, offset; | ||
487 | int cpu, ncpus; | ||
488 | struct timer_list *timer; | ||
489 | |||
490 | interval = HZ * 59 / *p; | ||
491 | offset = HZ; | ||
492 | ncpus = num_online_cpus(); | ||
493 | event_scan_interval = ncpus * interval; | ||
494 | for (cpu = 0; cpu < ncpus; ++cpu) { | ||
495 | timer = &per_cpu(heartbeat_timer, cpu); | ||
496 | setup_timer(timer, chrp_event_scan, 0); | ||
497 | timer->expires = jiffies + offset; | ||
498 | add_timer_on(timer, cpu); | ||
499 | offset += interval; | ||
500 | } | ||
501 | printk("RTAS Event Scan Rate: %u (%lu jiffies)\n", | ||
502 | *p, interval); | ||
503 | } | ||
504 | |||
479 | if (ppc_md.progress) | 505 | if (ppc_md.progress) |
480 | ppc_md.progress(" Have fun! ", 0x7777); | 506 | ppc_md.progress(" Have fun! ", 0x7777); |
481 | } | 507 | } |
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 21c8dc90d175..758e47fe8c1e 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h | |||
@@ -176,10 +176,6 @@ struct machdep_calls { | |||
176 | May be NULL. */ | 176 | May be NULL. */ |
177 | void (*init)(void); | 177 | void (*init)(void); |
178 | 178 | ||
179 | void (*heartbeat)(void); | ||
180 | unsigned long heartbeat_reset; | ||
181 | unsigned long heartbeat_count; | ||
182 | |||
183 | void (*setup_io_mappings)(void); | 179 | void (*setup_io_mappings)(void); |
184 | 180 | ||
185 | void (*early_serial_map)(void); | 181 | void (*early_serial_map)(void); |