aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/x86/include/asm/uv/uv_hub.h63
-rw-r--r--arch/x86/kernel/genx2apic_uv_x.c102
2 files changed, 164 insertions, 1 deletions
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index c6ad93e315c8..400776dba9b5 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -112,6 +112,16 @@
112 */ 112 */
113#define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_NODES * 2) 113#define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_NODES * 2)
114 114
115struct uv_scir_s {
116 struct timer_list timer;
117 unsigned long offset;
118 unsigned long last;
119 unsigned long idle_on;
120 unsigned long idle_off;
121 unsigned char state;
122 unsigned char enabled;
123};
124
115/* 125/*
116 * The following defines attributes of the HUB chip. These attributes are 126 * The following defines attributes of the HUB chip. These attributes are
117 * frequently referenced and are kept in the per-cpu data areas of each cpu. 127 * frequently referenced and are kept in the per-cpu data areas of each cpu.
@@ -130,7 +140,9 @@ struct uv_hub_info_s {
130 unsigned char blade_processor_id; 140 unsigned char blade_processor_id;
131 unsigned char m_val; 141 unsigned char m_val;
132 unsigned char n_val; 142 unsigned char n_val;
143 struct uv_scir_s scir;
133}; 144};
145
134DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); 146DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
135#define uv_hub_info (&__get_cpu_var(__uv_hub_info)) 147#define uv_hub_info (&__get_cpu_var(__uv_hub_info))
136#define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) 148#define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu))
@@ -162,6 +174,30 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
162 174
163#define UV_APIC_PNODE_SHIFT 6 175#define UV_APIC_PNODE_SHIFT 6
164 176
177/* Local Bus from cpu's perspective */
178#define LOCAL_BUS_BASE 0x1c00000
179#define LOCAL_BUS_SIZE (4 * 1024 * 1024)
180
181/*
182 * System Controller Interface Reg
183 *
184 * Note there are NO leds on a UV system. This register is only
185 * used by the system controller to monitor system-wide operation.
186 * There are 64 regs per node. With Nahelem cpus (2 cores per node,
187 * 8 cpus per core, 2 threads per cpu) there are 32 cpu threads on
188 * a node.
189 *
190 * The window is located at top of ACPI MMR space
191 */
192#define SCIR_WINDOW_COUNT 64
193#define SCIR_LOCAL_MMR_BASE (LOCAL_BUS_BASE + \
194 LOCAL_BUS_SIZE - \
195 SCIR_WINDOW_COUNT)
196
197#define SCIR_CPU_HEARTBEAT 0x01 /* timer interrupt */
198#define SCIR_CPU_ACTIVITY 0x02 /* not idle */
199#define SCIR_CPU_HB_INTERVAL (HZ) /* once per second */
200
165/* 201/*
166 * Macros for converting between kernel virtual addresses, socket local physical 202 * Macros for converting between kernel virtual addresses, socket local physical
167 * addresses, and UV global physical addresses. 203 * addresses, and UV global physical addresses.
@@ -276,6 +312,16 @@ static inline void uv_write_local_mmr(unsigned long offset, unsigned long val)
276 *uv_local_mmr_address(offset) = val; 312 *uv_local_mmr_address(offset) = val;
277} 313}
278 314
315static inline unsigned char uv_read_local_mmr8(unsigned long offset)
316{
317 return *((unsigned char *)uv_local_mmr_address(offset));
318}
319
320static inline void uv_write_local_mmr8(unsigned long offset, unsigned char val)
321{
322 *((unsigned char *)uv_local_mmr_address(offset)) = val;
323}
324
279/* 325/*
280 * Structures and definitions for converting between cpu, node, pnode, and blade 326 * Structures and definitions for converting between cpu, node, pnode, and blade
281 * numbers. 327 * numbers.
@@ -350,5 +396,20 @@ static inline int uv_num_possible_blades(void)
350 return uv_possible_blades; 396 return uv_possible_blades;
351} 397}
352 398
353#endif /* _ASM_X86_UV_UV_HUB_H */ 399/* Update SCIR state */
400static inline void uv_set_scir_bits(unsigned char value)
401{
402 if (uv_hub_info->scir.state != value) {
403 uv_hub_info->scir.state = value;
404 uv_write_local_mmr8(uv_hub_info->scir.offset, value);
405 }
406}
407static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
408{
409 if (uv_cpu_hub_info(cpu)->scir.state != value) {
410 uv_cpu_hub_info(cpu)->scir.state = value;
411 uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value);
412 }
413}
354 414
415#endif /* _ASM_X86_UV_UV_HUB_H */
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}