diff options
-rw-r--r-- | arch/x86/include/asm/uv/uv_hub.h | 63 | ||||
-rw-r--r-- | arch/x86/kernel/genx2apic_uv_x.c | 102 |
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 c6ad93e315c..400776dba9b 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 | ||
115 | struct 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 | |||
134 | DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); | 146 | DECLARE_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 | ||
315 | static inline unsigned char uv_read_local_mmr8(unsigned long offset) | ||
316 | { | ||
317 | return *((unsigned char *)uv_local_mmr_address(offset)); | ||
318 | } | ||
319 | |||
320 | static 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 */ |
400 | static 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 | } | ||
407 | static 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 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 | } |