aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/genx2apic_uv_x.c
diff options
context:
space:
mode:
authorMike Travis <travis@sgi.com>2008-10-24 18:24:29 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-27 07:40:45 -0400
commit7f1baa063e2582dd52d83bb31508e9e84468c666 (patch)
tree7111f53484822e0a95e8a053cd4aad6ddf9b2a41 /arch/x86/kernel/genx2apic_uv_x.c
parent5292ae11babca23c3ff82593630d2d7eebc350a9 (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.c102
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 dc6b46961523..84367d84bb10 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 */
365static 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
386static 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
403static 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 */
416static __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
434static __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
441static __init void uv_scir_register_cpu_notifier(void)
442{
443}
444
445static __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
455late_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}