diff options
author | Mike Travis <travis@sgi.com> | 2008-10-24 18:24:29 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-27 07:40:45 -0400 |
commit | 7f1baa063e2582dd52d83bb31508e9e84468c666 (patch) | |
tree | 7111f53484822e0a95e8a053cd4aad6ddf9b2a41 /arch/x86/kernel/genx2apic_uv_x.c | |
parent | 5292ae11babca23c3ff82593630d2d7eebc350a9 (diff) |
x86/uv: provide a System Activity Indicator driver
Impact: start per CPU heartbeat LED timers on SGI UV systems
The SGI UV system has no LEDS but uses one of the system controller
regs to indicate the online internal state of the cpu. There is a
heartbeat bit indicating that the cpu is responding to interrupts,
and an idle bit indicating whether the cpu is idle when the heartbeat
interrupt occurs. The current period is one second.
When a cpu panics, an error code is written by BIOS to this same reg.
This patchset provides the following:
* x86_64: Add base functionality for writing to the specific SCIR's
for each cpu.
* heartbeat: Invert "heartbeat" bit to indicate the cpu is
"interruptible". If the current thread is the idle thread,
then indicate system is "idle".
* if hotplug enabled, all bits are set (0xff) when the cpu is disabled.
Signed-off-by: Mike Travis <travis@sgi.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/genx2apic_uv_x.c')
-rw-r--r-- | arch/x86/kernel/genx2apic_uv_x.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/arch/x86/kernel/genx2apic_uv_x.c b/arch/x86/kernel/genx2apic_uv_x.c index dc6b4696152..84367d84bb1 100644 --- a/arch/x86/kernel/genx2apic_uv_x.c +++ b/arch/x86/kernel/genx2apic_uv_x.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/threads.h> | 12 | #include <linux/threads.h> |
13 | #include <linux/cpu.h> | ||
13 | #include <linux/cpumask.h> | 14 | #include <linux/cpumask.h> |
14 | #include <linux/string.h> | 15 | #include <linux/string.h> |
15 | #include <linux/ctype.h> | 16 | #include <linux/ctype.h> |
@@ -18,6 +19,8 @@ | |||
18 | #include <linux/bootmem.h> | 19 | #include <linux/bootmem.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
20 | #include <linux/hardirq.h> | 21 | #include <linux/hardirq.h> |
22 | #include <linux/timer.h> | ||
23 | #include <asm/current.h> | ||
21 | #include <asm/smp.h> | 24 | #include <asm/smp.h> |
22 | #include <asm/ipi.h> | 25 | #include <asm/ipi.h> |
23 | #include <asm/genapic.h> | 26 | #include <asm/genapic.h> |
@@ -357,6 +360,103 @@ static __init void uv_rtc_init(void) | |||
357 | } | 360 | } |
358 | 361 | ||
359 | /* | 362 | /* |
363 | * percpu heartbeat timer | ||
364 | */ | ||
365 | static void uv_heartbeat(unsigned long ignored) | ||
366 | { | ||
367 | struct timer_list *timer = &uv_hub_info->scir.timer; | ||
368 | unsigned char bits = uv_hub_info->scir.state; | ||
369 | |||
370 | /* flip heartbeat bit */ | ||
371 | bits ^= SCIR_CPU_HEARTBEAT; | ||
372 | |||
373 | /* are we the idle thread? */ | ||
374 | if (current->pid == 0) | ||
375 | bits &= ~SCIR_CPU_ACTIVITY; | ||
376 | else | ||
377 | bits |= SCIR_CPU_ACTIVITY; | ||
378 | |||
379 | /* update system controller interface reg */ | ||
380 | uv_set_scir_bits(bits); | ||
381 | |||
382 | /* enable next timer period */ | ||
383 | mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL); | ||
384 | } | ||
385 | |||
386 | static void __cpuinit uv_heartbeat_enable(int cpu) | ||
387 | { | ||
388 | if (!uv_cpu_hub_info(cpu)->scir.enabled) { | ||
389 | struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer; | ||
390 | |||
391 | uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY); | ||
392 | setup_timer(timer, uv_heartbeat, cpu); | ||
393 | timer->expires = jiffies + SCIR_CPU_HB_INTERVAL; | ||
394 | add_timer_on(timer, cpu); | ||
395 | uv_cpu_hub_info(cpu)->scir.enabled = 1; | ||
396 | } | ||
397 | |||
398 | /* check boot cpu */ | ||
399 | if (!uv_cpu_hub_info(0)->scir.enabled) | ||
400 | uv_heartbeat_enable(0); | ||
401 | } | ||
402 | |||
403 | static void __cpuinit uv_heartbeat_disable(int cpu) | ||
404 | { | ||
405 | if (uv_cpu_hub_info(cpu)->scir.enabled) { | ||
406 | uv_cpu_hub_info(cpu)->scir.enabled = 0; | ||
407 | del_timer(&uv_cpu_hub_info(cpu)->scir.timer); | ||
408 | } | ||
409 | uv_set_cpu_scir_bits(cpu, 0xff); | ||
410 | } | ||
411 | |||
412 | #ifdef CONFIG_HOTPLUG_CPU | ||
413 | /* | ||
414 | * cpu hotplug notifier | ||
415 | */ | ||
416 | static __cpuinit int uv_scir_cpu_notify(struct notifier_block *self, | ||
417 | unsigned long action, void *hcpu) | ||
418 | { | ||
419 | long cpu = (long)hcpu; | ||
420 | |||
421 | switch (action) { | ||
422 | case CPU_ONLINE: | ||
423 | uv_heartbeat_enable(cpu); | ||
424 | break; | ||
425 | case CPU_DOWN_PREPARE: | ||
426 | uv_heartbeat_disable(cpu); | ||
427 | break; | ||
428 | default: | ||
429 | break; | ||
430 | } | ||
431 | return NOTIFY_OK; | ||
432 | } | ||
433 | |||
434 | static __init void uv_scir_register_cpu_notifier(void) | ||
435 | { | ||
436 | hotcpu_notifier(uv_scir_cpu_notify, 0); | ||
437 | } | ||
438 | |||
439 | #else /* !CONFIG_HOTPLUG_CPU */ | ||
440 | |||
441 | static __init void uv_scir_register_cpu_notifier(void) | ||
442 | { | ||
443 | } | ||
444 | |||
445 | static __init int uv_init_heartbeat(void) | ||
446 | { | ||
447 | int cpu; | ||
448 | |||
449 | if (is_uv_system()) | ||
450 | for_each_online_cpu(cpu) | ||
451 | uv_heartbeat_enable(cpu); | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | late_initcall(uv_init_heartbeat); | ||
456 | |||
457 | #endif /* !CONFIG_HOTPLUG_CPU */ | ||
458 | |||
459 | /* | ||
360 | * Called on each cpu to initialize the per_cpu UV data area. | 460 | * Called on each cpu to initialize the per_cpu UV data area. |
361 | * ZZZ hotplug not supported yet | 461 | * ZZZ hotplug not supported yet |
362 | */ | 462 | */ |
@@ -452,6 +552,7 @@ void __init uv_system_init(void) | |||
452 | uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper; | 552 | uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper; |
453 | uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; | 553 | uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; |
454 | uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id; | 554 | uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id; |
555 | uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu; | ||
455 | uv_node_to_blade[nid] = blade; | 556 | uv_node_to_blade[nid] = blade; |
456 | uv_cpu_to_blade[cpu] = blade; | 557 | uv_cpu_to_blade[cpu] = blade; |
457 | max_pnode = max(pnode, max_pnode); | 558 | max_pnode = max(pnode, max_pnode); |
@@ -468,4 +569,5 @@ void __init uv_system_init(void) | |||
468 | map_mmioh_high(max_pnode); | 569 | map_mmioh_high(max_pnode); |
469 | 570 | ||
470 | uv_cpu_init(); | 571 | uv_cpu_init(); |
572 | uv_scir_register_cpu_notifier(); | ||
471 | } | 573 | } |